<!DOCTYPE html>
<html lang="en-US" dir="ltr">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>持久化 | VitePress</title>
    <meta name="description" content="A VitePress site">
    <link rel="preload stylesheet" href="/notebook/assets/style.3dbfd0c2.css" as="style">
    
    <script type="module" src="/notebook/assets/app.8aaa4cbe.js"></script>
    <link rel="preload" href="/notebook/assets/inter-roman-latin.2ed14f66.woff2" as="font" type="font/woff2" crossorigin="">
    <link rel="modulepreload" href="/notebook/assets/chunks/framework.1336c4e5.js">
    <link rel="modulepreload" href="/notebook/assets/chunks/theme.20cddc0c.js">
    <link rel="modulepreload" href="/notebook/assets/2、数据库_Redis_Redis高级.md.1d5872f6.lean.js">
    <script id="check-dark-light">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
  </head>
  <body>
    <div id="app"><div class="Layout" data-v-255ec12d><!--[--><!--]--><!--[--><span tabindex="-1" data-v-ae3e3f51></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-ae3e3f51> Skip to content </a><!--]--><!----><header class="VPNav" data-v-255ec12d data-v-7e5bc4a5><div class="VPNavBar has-sidebar" data-v-7e5bc4a5 data-v-0937f67c><div class="container" data-v-0937f67c><div class="title" data-v-0937f67c><div class="VPNavBarTitle has-sidebar" data-v-0937f67c data-v-86d1bed8><a class="title" href="/notebook/" data-v-86d1bed8><!--[--><!--]--><!--[--><img class="VPImage logo" src="/notebook/Vue.png" alt data-v-8426fc1a><!--]--><!--[-->任硕的文档<!--]--><!--[--><!--]--></a></div></div><div class="content" data-v-0937f67c><div class="curtain" data-v-0937f67c></div><div class="content-body" data-v-0937f67c><!--[--><!--]--><div class="VPNavBarSearch search" style="--vp-meta-key:&#39;Meta&#39;;" data-v-0937f67c><!--[--><!----><div id="docsearch"><button type="button" class="DocSearch DocSearch-Button" aria-label="Search"><span class="DocSearch-Button-Container"><svg class="DocSearch-Search-Icon" width="20" height="20" viewBox="0 0 20 20" aria-label="search icon"><path d="M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z" stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"></path></svg><span class="DocSearch-Button-Placeholder">Search</span></span><span class="DocSearch-Button-Keys"><kbd class="DocSearch-Button-Key"></kbd><kbd class="DocSearch-Button-Key">K</kbd></span></button></div><!--]--></div><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-0937f67c data-v-7f418b0f><span id="main-nav-aria-label" class="visually-hidden" data-v-7f418b0f>Main Navigation</span><!--[--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-a7b5672a><span class="text" data-v-a7b5672a><!----><span data-v-a7b5672a>Java学前端</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-a7b5672a><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuGroup" data-v-e7ea1737 data-v-69e747b5><!----><!--[--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/Java%E5%AD%A6%E5%89%8D%E7%AB%AF/HTML+JS.html" data-v-2f2cfafc><!--[-->HTML+JS<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/Java%E5%AD%A6%E5%89%8D%E7%AB%AF/CSS.html" data-v-2f2cfafc><!--[-->CSS<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/Java%E5%AD%A6%E5%89%8D%E7%AB%AF/Vue2+%E7%BB%84%E4%BB%B6.html" data-v-2f2cfafc><!--[-->Vue2+组件<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/Java%E5%AD%A6%E5%89%8D%E7%AB%AF/Vue3+%E7%BB%84%E4%BB%B6.html" data-v-2f2cfafc><!--[-->Vue3+组件<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/Java%E5%AD%A6%E5%89%8D%E7%AB%AF/React.html" data-v-2f2cfafc><!--[-->React<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-a7b5672a><span class="text" data-v-a7b5672a><!----><span data-v-a7b5672a>软件测试</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-a7b5672a><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuGroup" data-v-e7ea1737 data-v-69e747b5><!----><!--[--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95/%E6%B5%8B%E8%AF%95%E5%9F%BA%E7%A1%80.html" data-v-2f2cfafc><!--[-->测试基础<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95/%E5%8E%8B%E5%8A%9B%E6%B5%8B%E8%AF%95.html" data-v-2f2cfafc><!--[-->压力测试<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-a7b5672a><span class="text" data-v-a7b5672a><!----><span data-v-a7b5672a>多线程</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-a7b5672a><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuGroup" data-v-e7ea1737 data-v-69e747b5><!----><!--[--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E5%B9%B6%E5%8F%91%20&amp;%20%E5%A4%9A%E7%BA%BF%E7%A8%8B/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-2f2cfafc><!--[-->基础篇<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E5%B9%B6%E5%8F%91%20&amp;%20%E5%A4%9A%E7%BA%BF%E7%A8%8B/%E5%B9%B6%E5%8F%91%E5%AE%8C%E5%96%84.html" data-v-2f2cfafc><!--[-->进阶篇<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-a7b5672a><span class="text" data-v-a7b5672a><!----><span data-v-a7b5672a>开发工具</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-a7b5672a><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuGroup" data-v-e7ea1737 data-v-69e747b5><!----><!--[--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/IDEA/Chrome.html" data-v-2f2cfafc><!--[-->Chrome<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/IDEA/IDEA%E5%9F%BA%E7%A1%80.html" data-v-2f2cfafc><!--[-->IDEA基础<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/IDEA/IDEA%E6%8F%92%E4%BB%B6.html" data-v-2f2cfafc><!--[-->IDEA插件<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/IDEA/VS%20Code.html" data-v-2f2cfafc><!--[-->VS Code<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-a7b5672a><span class="text" data-v-a7b5672a><!----><span data-v-a7b5672a>消息中间件</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-a7b5672a><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuGroup" data-v-e7ea1737 data-v-69e747b5><!----><!--[--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6/RabbitMQ.html" data-v-2f2cfafc><!--[-->RabbitMQ<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6/RocketMQ.html" data-v-2f2cfafc><!--[-->RocketMQ<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6/Kafka.html" data-v-2f2cfafc><!--[-->Kafka<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6/Canal.html" data-v-2f2cfafc><!--[-->Canal<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-0937f67c data-v-f6a63727><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title="toggle dark mode" aria-checked="false" data-v-f6a63727 data-v-82b282f1 data-v-f3c41672><span class="check" data-v-f3c41672><span class="icon" data-v-f3c41672><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-82b282f1><path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"></path><path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"></path><path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"></path><path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"></path><path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"></path><path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"></path><path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"></path><path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"></path><path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="moon" data-v-82b282f1><path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"></path></svg><!--]--></span></span></button></div><div class="VPSocialLinks VPNavBarSocialLinks social-links" data-v-0937f67c data-v-0394ad82 data-v-7bc22406><!--[--><a class="VPSocialLink no-icon" href="https://github.com/renshuo123/renshuo123.github.io" aria-label="github" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></a><a class="VPSocialLink no-icon" href="#" aria-label="twitter" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Twitter</title><path d="M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z"/></svg></a><a class="VPSocialLink no-icon" href="https://github.com/" aria-label target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg t="1676028692954" class="icon" ...</path></svg></a><!--]--></div><div class="VPFlyout VPNavBarExtra extra" data-v-0937f67c data-v-40855f84 data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" aria-label="extra navigation" data-v-a7b5672a><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="icon" data-v-a7b5672a><circle cx="12" cy="12" r="2"></circle><circle cx="19" cy="12" r="2"></circle><circle cx="5" cy="12" r="2"></circle></svg></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><!----><!--[--><!--[--><!----><div class="group" data-v-40855f84><div class="item appearance" data-v-40855f84><p class="label" data-v-40855f84>Appearance</p><div class="appearance-action" data-v-40855f84><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title="toggle dark mode" aria-checked="false" data-v-40855f84 data-v-82b282f1 data-v-f3c41672><span class="check" data-v-f3c41672><span class="icon" data-v-f3c41672><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-82b282f1><path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"></path><path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"></path><path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"></path><path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"></path><path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"></path><path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"></path><path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"></path><path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"></path><path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="moon" data-v-82b282f1><path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"></path></svg><!--]--></span></span></button></div></div></div><div class="group" data-v-40855f84><div class="item social-links" data-v-40855f84><div class="VPSocialLinks social-links-list" data-v-40855f84 data-v-7bc22406><!--[--><a class="VPSocialLink no-icon" href="https://github.com/renshuo123/renshuo123.github.io" aria-label="github" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></a><a class="VPSocialLink no-icon" href="#" aria-label="twitter" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Twitter</title><path d="M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z"/></svg></a><a class="VPSocialLink no-icon" href="https://github.com/" aria-label target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg t="1676028692954" class="icon" ...</path></svg></a><!--]--></div></div></div><!--]--><!--]--></div></div></div><!--[--><!--]--><button type="button" class="VPNavBarHamburger hamburger" aria-label="mobile navigation" aria-expanded="false" aria-controls="VPNavScreen" data-v-0937f67c data-v-e5dd9c1c><span class="container" data-v-e5dd9c1c><span class="top" data-v-e5dd9c1c></span><span class="middle" data-v-e5dd9c1c></span><span class="bottom" data-v-e5dd9c1c></span></span></button></div></div></div></div><!----></header><div class="VPLocalNav reached-top" data-v-255ec12d data-v-5cfd5582><button class="menu" aria-expanded="false" aria-controls="VPSidebarNav" data-v-5cfd5582><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="menu-icon" data-v-5cfd5582><path d="M17,11H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,11,17,11z"></path><path d="M21,7H3C2.4,7,2,6.6,2,6s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,7,21,7z"></path><path d="M21,15H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,15,21,15z"></path><path d="M17,19H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,19,17,19z"></path></svg><span class="menu-text" data-v-5cfd5582>Menu</span></button><div class="VPLocalNavOutlineDropdown" style="--vp-vh:0px;" data-v-5cfd5582 data-v-18201f51><button data-v-18201f51>Return to top</button><!----></div></div><aside class="VPSidebar" data-v-255ec12d data-v-845b8fc6><div class="curtain" data-v-845b8fc6></div><nav class="nav" id="VPSidebarNav" aria-labelledby="sidebar-aria-label" tabindex="-1" data-v-845b8fc6><span class="visually-hidden" id="sidebar-aria-label" data-v-845b8fc6> Sidebar Navigation </span><!--[--><!--]--><!--[--><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>Java</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Java/Java%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Java基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Java/Java%E6%96%B0%E7%89%B9%E6%80%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Java新特性</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Java/Java%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Java进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Java/Java%E9%9B%86%E5%90%88.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Java集合</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Java/Java%E9%AB%98%E7%BA%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Java高级</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>Linux</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Linux/Linux%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Linux基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Linux/Linux%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Linux新特性</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Linux/Shell.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Shell脚本</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Linux/%E5%AE%9E%E7%94%A8%E8%84%9A%E6%9C%AC.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>实用脚本</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Linux/%E8%BD%AF%E4%BB%B6%E9%83%A8%E7%BD%B2.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>软件部署</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>Nginx</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Nginx/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Nginx/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Nginx/%E5%AE%9E%E6%88%98%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>实战篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Nginx/%E9%9D%A2%E8%AF%95%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>面试篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>SSM</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/SSM/Maven.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Maven</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/SSM/Spring.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Spring</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/SSM/SpringMVC.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringMVC</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/SSM/SpringBatch.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringBatch</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>SpringBoot</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/3%E3%80%81SpringBoot/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/3%E3%80%81SpringBoot/%E5%BA%94%E7%94%A8%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>应用篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/3%E3%80%81SpringBoot/%E6%96%B0%E7%89%B9%E6%80%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>新特性</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/3%E3%80%81SpringBoot/%E8%BF%90%E7%BB%B4&amp;%E5%8E%9F%E7%90%86.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>运维&原理</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>SpringCloud</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringCloud</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/%E5%BF%85%E5%A4%87/Sentinel.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Sentinel</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>SpringSecurity</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/SpringSecurity/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringSecurity基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/SpringSecurity/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringSecurity进阶篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/SpringSecurity/%E9%AB%98%E7%BA%A7%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringSecurity高级篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>Mybatis & MybatisPlus</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Mybatis&amp;MybatisPlus/Mybatis.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Mybatis</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Mybatis&amp;MybatisPlus/MybatisPlus.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MybatisPlus</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Mybatis&amp;MybatisPlus/JPA.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>JPA</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>Git & ChatGPT</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/5%E3%80%81%E8%BF%90%E7%BB%B4/Git.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Git</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/5%E3%80%81%E8%BF%90%E7%BB%B4/Github.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Github</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/5%E3%80%81%E8%BF%90%E7%BB%B4/ChatGPT.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>ChatGPT</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/5%E3%80%81%E8%BF%90%E7%BB%B4/Jenkins.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Jenkins</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/5%E3%80%81%E8%BF%90%E7%BB%B4/Netty.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Netty</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible has-active" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>数据库</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>MySQL</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MySQL基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MySQL进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E4%BC%98%E5%8C%96.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MySQL优化</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E8%AE%BE%E8%AE%A1.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MySQL设计</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E8%BF%90%E7%BB%B4.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MySQL运维</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>分库分表</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible has-active" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>Redis</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Redis基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E4%BC%98%E5%8C%96.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Redis优化</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E5%8E%9F%E7%90%86.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Redis原理</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E9%AB%98%E7%BA%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Redis高级</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E5%AE%9E%E6%88%98.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Redis实战</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/%E6%9C%AC%E5%9C%B0%E7%BC%93%E5%AD%98.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>本地缓存</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>MongoDB</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MongoDB/%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MongoDB基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MongoDB/%E6%95%B4%E5%90%88.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MongoDB进阶</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>ElasticSearch</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/ElasticSearch/1%E3%80%81ES%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>ES基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/ElasticSearch/3%E3%80%81ES%E9%AB%98%E7%BA%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>ES高级</p><!--]--></a><!----></div><!----></div><!--]--></div></section><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/influxdb.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>InfluxDB</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Neo4j.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Neo4j</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>高并发 & 秒杀 & 分布式</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%B8%89%E9%AB%98/%E5%88%86%E5%B8%83%E5%BC%8F.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>分布式理论</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/%E5%BF%85%E5%A4%87/%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>分布式锁</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%B8%89%E9%AB%98/%E7%A7%92%E6%9D%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>秒杀</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%B8%89%E9%AB%98/%E9%AB%98%E5%8F%AF%E7%94%A8.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>高可用</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%B8%89%E9%AB%98/%E9%AB%98%E5%B9%B6%E5%8F%91.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>高并发</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>云原生</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%BA%91%E5%8E%9F%E7%94%9F/Docker.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Docker</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%BA%91%E5%8E%9F%E7%94%9F/K8S.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>K8S</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>可视化 & 监控</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E5%8F%AF%E8%A7%86%E5%8C%96%20&amp;%20%E7%9B%91%E6%8E%A7/%E7%9B%91%E6%8E%A7%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>监控基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E5%8F%AF%E8%A7%86%E5%8C%96%20&amp;%20%E7%9B%91%E6%8E%A7/%E7%9B%91%E6%8E%A7%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>监控进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E5%8F%AF%E8%A7%86%E5%8C%96%20&amp;%20%E7%9B%91%E6%8E%A7/%E5%8F%AF%E8%A7%86%E5%8C%96%E5%A4%A7%E5%B1%8F.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>可视化大屏</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E5%8F%AF%E8%A7%86%E5%8C%96%20&amp;%20%E7%9B%91%E6%8E%A7/Zabbix.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Zabbix</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>学前端</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>HTML+CSS</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/1%E3%80%81HTML+CSS/HTML%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>HTML基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/1%E3%80%81HTML+CSS/CSS%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>CSS基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/1%E3%80%81HTML+CSS/%E7%BD%91%E9%A1%B5%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>网页进阶</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>JS+TS</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/2%E3%80%81JS+TS/JS%20%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>JS基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/2%E3%80%81JS+TS/JS%20%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>JS进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/2%E3%80%81JS+TS/ES6%20%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>ES6基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/2%E3%80%81JS+TS/ES6%20%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>ES6进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/2%E3%80%81JS+TS/TypeScript.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>TS基础</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>NodeJS</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/4%E3%80%81Node/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Node基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/4%E3%80%81Node/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Node进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/4%E3%80%81Node/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>项目实战</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>Vue</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/3%E3%80%81Vue/Vue3/Vue3%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Vue3进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/3%E3%80%81Vue/Vue3/Vue3%E9%AB%98%E7%BA%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Vue3高级</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/3%E3%80%81Vue/Vue3/Vue3%E6%96%B0%E8%AF%AD%E6%B3%95.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Vue3新语法</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/3%E3%80%81Vue/Vue2/Vue2%E9%A1%B9%E7%9B%AE.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>项目实战</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>小程序</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/5%E3%80%81%E5%B0%8F%E7%A8%8B%E5%BA%8F/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>小程序基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/5%E3%80%81%E5%B0%8F%E7%A8%8B%E5%BA%8F/%E5%B0%8F%E7%A8%8B%E5%BA%8F%E4%BC%98%E5%8C%96.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>小程序优化</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/5%E3%80%81%E5%B0%8F%E7%A8%8B%E5%BA%8F/uniapp.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>uniapp</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/5%E3%80%81%E5%B0%8F%E7%A8%8B%E5%BA%8F/%E5%B0%8F%E7%A8%8B%E5%BA%8F%E9%A1%B9%E7%9B%AE.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>项目实战</p><!--]--></a><!----></div><!----></div><!--]--></div></section><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>计算机基础</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>数据结构</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>操作系统</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>设计模式</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E7%BD%91%E7%BB%9C%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>计算机网络</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/UML.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>UML</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E7%AE%97%E6%B3%95/LeetCode.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>LeetCode</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>项目实战</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>云尚办公</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E4%BA%91%E5%B0%9A%E5%8A%9E%E5%85%AC/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>小兔鲜</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E5%B0%8F%E5%85%94%E9%B2%9C/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E5%B0%8F%E5%85%94%E9%B2%9C/%E8%BF%9B%E9%98%B6%E7%AF%871.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇1</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E5%B0%8F%E5%85%94%E9%B2%9C/%E8%BF%9B%E9%98%B6%E7%AF%872.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇2</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>地图</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>苍穹外卖</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E8%8B%8D%E7%A9%B9%E5%A4%96%E5%8D%96/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>黑马头条</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E9%BB%91%E9%A9%AC%E5%A4%B4%E6%9D%A1/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E9%BB%91%E9%A9%AC%E5%A4%B4%E6%9D%A1/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E9%BB%91%E9%A9%AC%E5%A4%B4%E6%9D%A1/%E8%BF%9B%E9%98%B6%E7%AF%872.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇2</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E9%BB%91%E9%A9%AC%E5%A4%B4%E6%9D%A1/%E9%AB%98%E7%BA%A7%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>高级篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E6%94%AF%E4%BB%98.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>支付</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E9%A1%B9%E7%9B%AE%E6%8E%A8%E8%8D%90.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>项目推荐</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0" data-v-845b8fc6 data-v-9b797284><!----><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/team.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>团队成员</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><!--]--><!--[--><!--]--></nav></aside><div class="VPContent has-sidebar" id="VPContent" data-v-255ec12d data-v-669faec9><div class="VPDoc has-sidebar has-aside" data-v-669faec9 data-v-6b87e69f><!--[--><!--]--><div class="container" data-v-6b87e69f><div class="aside" data-v-6b87e69f><div class="aside-curtain" data-v-6b87e69f></div><div class="aside-container" data-v-6b87e69f><div class="aside-content" data-v-6b87e69f><div class="VPDocAside" data-v-6b87e69f data-v-3f215769><!--[--><!--]--><!--[--><!--]--><div class="VPDocAsideOutline" data-v-3f215769 data-v-ff0f39c8><div class="content" data-v-ff0f39c8><div class="outline-marker" data-v-ff0f39c8></div><div class="outline-title" data-v-ff0f39c8>On this page</div><nav aria-labelledby="doc-outline-aria-label" data-v-ff0f39c8><span class="visually-hidden" id="doc-outline-aria-label" data-v-ff0f39c8> Table of Contents for current page </span><ul class="root" data-v-ff0f39c8 data-v-d0ee3533><!--[--><!--]--></ul></nav></div></div><!--[--><!--]--><div class="spacer" data-v-3f215769></div><!--[--><!--]--><!----><!--[--><!--]--><!--[--><!--]--></div></div></div></div><div class="content" data-v-6b87e69f><div class="content-container" data-v-6b87e69f><!--[--><!--]--><!----><main class="main" data-v-6b87e69f><div style="position:relative;" class="vp-doc _notebook_2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93_Redis_Redis%E9%AB%98%E7%BA%A7" data-v-6b87e69f><div><h1 id="持久化" tabindex="-1">持久化 <a class="header-anchor" href="#持久化" aria-label="Permalink to &quot;持久化&quot;">​</a></h1><blockquote><p>Redis 是内存数据库，数据都是存储在内存中，<strong>为了避免进程退出导致数据的永久丢失，需要定期将 Redis 中的数据以数据或命令的形式从内存保存到本地磁盘</strong>。当下次 Redis 重启时，利用持久化文件进行数据恢复。Redis 提供了 RDB 和 AOF 两种持久化机制，前者将当前的数据保存到磁盘，后者则是将每次执行的写命令保存到磁盘（类似于 MySQL 的 Binlog）。</p></blockquote><h2 id="rdb-快照持久化" tabindex="-1">RDB 快照持久化 <a class="header-anchor" href="#rdb-快照持久化" aria-label="Permalink to &quot;RDB 快照持久化&quot;">​</a></h2><h3 id="rdb概述" tabindex="-1">RDB概述 <a class="header-anchor" href="#rdb概述" aria-label="Permalink to &quot;RDB概述&quot;">​</a></h3><blockquote><p>RDB全称Redis Database Backup file（Redis数据备份文件），也被叫做Redis数据快照。简单来说就是把内存中的所有数据都记录到磁盘中。当Redis实例故障重启后，从磁盘读取快照文件，恢复数据。</p></blockquote><blockquote><p>快照文件称为RDB文件，默认是保存在当前运行目录。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208101750394.png" alt="image-20220810175048314" style="zoom:67%;"><p>快照文件称为RDB文件，默认是保存在当前运行目录。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209141700016.png" alt="image-20220914170026614" style="zoom:80%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209141812431.png" alt="image-20220914181248310" style="zoom:80%;"><table><thead><tr><th style="text-align:left;">命令</th><th style="text-align:left;">SAVE</th><th style="text-align:left;">BGSAVE</th></tr></thead><tbody><tr><td style="text-align:left;">IO 类型</td><td style="text-align:left;">同步</td><td style="text-align:left;">异步</td></tr><tr><td style="text-align:left;">是否阻塞</td><td style="text-align:left;">全程阻塞</td><td style="text-align:left;">fork 时发生阻塞</td></tr><tr><td style="text-align:left;">复杂度</td><td style="text-align:left;">O(n)</td><td style="text-align:left;">O(n)</td></tr><tr><td style="text-align:left;">优点</td><td style="text-align:left;">不会消耗额外的内存</td><td style="text-align:left;">不阻塞客户端</td></tr><tr><td style="text-align:left;">缺点</td><td style="text-align:left;">阻塞客户端</td><td style="text-align:left;">fork 子进程消耗内存</td></tr></tbody></table><blockquote><p>Redis停机时会自动执行一次RDB，RDB 文件是一个单文件的全量数据，很适合数据的容灾备份与恢复，通过 RDB 文件恢复数据库耗时较短，通常 1G 的快照文件载入内存只需 20s 左右。Redis 提供了手动触发保存、自动保存间隔两种 RDB 文件的生成方式，下面先介绍 RDB 的创建和载入过程。在指定的时间间隔内将内存中的数据集快照写入磁盘， 也就是行话讲的Snapshot快照，它恢复时是将快照文件直接读到内存里。</p></blockquote><h3 id="rdb配置⭐" tabindex="-1">RDB配置⭐ <a class="header-anchor" href="#rdb配置⭐" aria-label="Permalink to &quot;RDB配置⭐&quot;">​</a></h3><h4 id="核心配置⭐" tabindex="-1">核心配置⭐ <a class="header-anchor" href="#核心配置⭐" aria-label="Permalink to &quot;核心配置⭐&quot;">​</a></h4><blockquote><p>Redis 服务器默认是通过 RDB 方式完成持久化的，对应 redis.conf 文件的配置项如下：</p><p>如果要关闭RDB，只需要写成save &quot;&quot;即可</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.11/202206091311166.png" alt="image-20220609131101090" style="zoom:80%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041003704.png" alt="image-20220504100333644" style="zoom:80%;"><blockquote><p>因为 BGSAVE 命令可以在不阻塞服务器进程的情况下执行，所以 Redis 的配置文件 redis.conf 提供了一个 save 选项，让服务器每隔一段时间自动执行一次 BGSAVE 命令。用户可以通过 save 选项设置多个保存条件，只要其中任意一个条件被满足，服务器就会执行 BGSAVE 命令。Redis 配置文件 redis.conf 默认配置了以下 3 个保存条件：</p></blockquote><p>那么只要满足以下 3 个条件中的任意一个，BGSAVE 命令就会被自动执行：</p><blockquote><ul><li>服务器在 10 秒之内，对数据库进行了至少 1 次修改则触发RDB。</li><li>服务器在 300 秒之内，对数据库进行了至少 10 次修改则触发RDB。</li><li>服务器在 60 秒之内，对数据库进行了至少 10000 次修改则触发RDB。</li></ul></blockquote><blockquote><p>比如通过命令 SET msg &quot;hello&quot; 插入一条键值对，等待 10秒后 Reids 服务器进程自动触发保存：</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209141822960.png" alt="image-20220914182259862" style="zoom:80%;"><blockquote><p>Redis 服务器会周期性地操作 serverCron 函数，这个函数每隔 100 毫秒就会执行一次，它的一项任务就是检查 save 选项所设置的保存条件是否满足，如果满足的话，就自动执行 BGSAVE 命令。</p></blockquote><h4 id="stop-writes-on-bgsave-error" tabindex="-1">stop-writes-on-bgsave-error <a class="header-anchor" href="#stop-writes-on-bgsave-error" aria-label="Permalink to &quot;stop-writes-on-bgsave-error&quot;">​</a></h4><blockquote><p>当Redis无法写入磁盘的话，直接关掉Redis的写操作。推荐yes。<strong>注意</strong>：如果后台保存过程将再次开始工作，<code>Redis</code>将自动允许再次写入。</p></blockquote><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">stop</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">writes</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">on</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">bgsave</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">error yes</span></span></code></pre></div><p>当<code>bgsave</code>出现错误时，<code>Redis</code>是否停止执行写命令；</p><blockquote><ul><li>如果为<code>yes</code>，则当硬盘出现问题时，<code>Redis</code>将停止接受写入操作，这样我们可以及时发现，避免数据的大量丢失；</li><li>如果为<code>no</code>，则<code>Redis</code>无视<code>bgsave</code>的错误继续执行写命令。</li></ul></blockquote><blockquote><p>如果已经设置了对<code>Redis</code>服务器的正确监视和持久性，即采用了其他手段发现和控制数据完整性，可能希望禁用此功能，以便即使在磁盘、权限等方面出现问题时，<code>Redis</code>仍能正常工作。</p></blockquote><h4 id="rdbchecksum检查完整性" tabindex="-1">rdbchecksum检查完整性 <a class="header-anchor" href="#rdbchecksum检查完整性" aria-label="Permalink to &quot;rdbchecksum检查完整性&quot;">​</a></h4><blockquote><p>从<code>RDB</code>版本<code>5</code>开始，在存储快照后，还可以使用<code>CRC64</code>算法来进行数据校验，<code>CRC64</code>校验放在文件的末尾。开启之后，保存和加载<code>RDB</code>文件时会增加大约<code>10%</code>的性能消耗，如果希望获取到最大的性能提升，可以关闭此功能。禁用<strong>校验和</strong>创建的<code>RDB</code>文件的校验和为零，这将告诉加载代码跳过检查。</p></blockquote><div class="language-assembly"><button title="Copy Code" class="copy"></button><span class="lang">assembly</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">rdbchecksum yes</span></span></code></pre></div><blockquote><p>是否开启 RDB 文件的校验，在写入文件和读取文件时都起作用。关闭 checksum 在写入文件和启动文件时大约能带来 10% 的性能提升，但是数据损坏时无法发现。如果希望获取到最大的性能提升，可以关闭此功能推荐yes.</p></blockquote><h3 id="原理部分" tabindex="-1">原理部分 <a class="header-anchor" href="#原理部分" aria-label="Permalink to &quot;原理部分&quot;">​</a></h3><h4 id="执行时机和bgsave原理" tabindex="-1">执行时机和bgsave原理 <a class="header-anchor" href="#执行时机和bgsave原理" aria-label="Permalink to &quot;执行时机和bgsave原理&quot;">​</a></h4><blockquote><p>RDB持久化在执行时机：执行save命令、执行bgsave命令、Redis停机时、触发RDB条件时</p></blockquote><blockquote><p>bgsave开始时会fork主进程得到子进程，子进程共享主进程的内存数据。完成fork后读取内存数据并写入 RDB 文件。fork采用的是copy-on-write技术：</p></blockquote><ul><li>当主进程执行读操作时，访问共享内存；</li><li>当主进程执行写操作时，则会拷贝一份数据，执行写操作。</li></ul><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041007713.png" alt="image-20220504100717626" style="zoom:80%;"><blockquote><p>RDB方式bgsave的基本流程？</p><ul><li>fork主进程得到一个子进程，共享内存空间</li><li>子进程读取内存数据并写入新的RDB文件</li><li>用新RDB文件替换旧的RDB文件。</li></ul></blockquote><h4 id="启动自动载入" tabindex="-1">启动自动载入 <a class="header-anchor" href="#启动自动载入" aria-label="Permalink to &quot;启动自动载入&quot;">​</a></h4><blockquote><p>和使用 SAVE 和 BGSAVE 命令创建 RDB 文件不同，Redis 没有专门提供用于载入 RDB 文件的命令，RDB 文件的载入过程是在 Redis 服务器启动时自动完成的。启动时只要在指定目录检测到 RDB 文件的存在，Redis 就会通过 rdbLoad 函数自动载入 RDB 文件。</p></blockquote><blockquote><p>下面是 Redis 服务器启动时打印的日志，倒数第 2 条日志是在成功载入 RDB 文件后打印的。</p></blockquote><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">server </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">etc</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">conf</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209141823861.png" alt="image-20220914182349758" style="zoom:80%;"><blockquote><p>由于 AOF 文件属于增量的写入命令备份，RDB 文件属于全量的数据备份，所以更新频率比 RDB 文件的更新频率高。所以如果 Redis 服务器开启了 AOF 持久化功能，那么服务器会优先使用 AOF 文件来还原数据库状态；只有在 AOF 的持久化功能处于关闭状态时，服务器才使用使用 RDB 文件还原数据库状态</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208101842547.png" alt="image-20220810184213464" style="zoom:67%;"><h4 id="rdb缺点" tabindex="-1">RDB缺点 <a class="header-anchor" href="#rdb缺点" aria-label="Permalink to &quot;RDB缺点&quot;">​</a></h4><blockquote><ul><li>RDB执行间隔时间长，两次RDB之间写入数据有丢失的风险</li><li>fork子进程、压缩、写出RDB文件都比较耗时</li></ul></blockquote><h2 id="aof-追加文件" tabindex="-1">AOF 追加文件 <a class="header-anchor" href="#aof-追加文件" aria-label="Permalink to &quot;AOF 追加文件&quot;">​</a></h2><h3 id="aof概述" tabindex="-1">AOF概述 <a class="header-anchor" href="#aof概述" aria-label="Permalink to &quot;AOF概述&quot;">​</a></h3><blockquote><p>AOF全称为Append Only File（追加文件）。Redis处理的每一个写命令都会记录在AOF文件，可以看做是命令日志文件，它会把 Redis 服务器每次执行的写命令记录到一个日志文件中，当服务器重启时再次执行 AOF 文件中的命令来恢复数据。</p></blockquote><blockquote><p><strong>当 AOF 持久化功能开启时，Redis 服务器启动时优先执行 AOF 文件的命令恢复数据，只有当 AOF 功能关闭时，才会优先载入 RDB 快照的文件数据</strong>。</p></blockquote><blockquote><p>AOF（Append Only File）：AOF 持久化记录服务器接收到的每个写入操作，这些操作将在服务器启动时再次被执行，重建原始数据集。这种持久性的方法能够确保比 RDB 快照更持久，因为它是一个仅附加文件。随着操作的发生，我们将它们缓冲到日志中，但它们还没有被持久化。该日志与我们运行的实际命令一致，以便在需要时进行重放。然后，如果可能，我们使用 fsync 将其刷新到磁盘（当此运行可配置时），它将被持久化。缺点是格式不紧凑，并且比 RDB 文件使用更多的磁盘。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209141826941.png" alt="image-20220914182625847" style="zoom:80%;"><blockquote><p>AOF 的主要作用是解决了数据持久化的实时性，目前已经成为了 Redis 持久化的主流方式</p><p>AOF和RDB同时开启，系统默认取AOF的数据（数据不会存在丢失）</p></blockquote><h3 id="开启和同步频率⭐" tabindex="-1">开启和同步频率⭐ <a class="header-anchor" href="#开启和同步频率⭐" aria-label="Permalink to &quot;开启和同步频率⭐&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.11/202206091313570.png" alt="image-20220609131352476" style="zoom:80%;"><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 备份RDB和AOF文件存放路径</span></span>
<span class="line"><span style="color:#A6ACCD;">dir </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">usr</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">local</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">var</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">db</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">/</span></span></code></pre></div><h3 id="其他配置项⭐" tabindex="-1">其他配置项⭐ <a class="header-anchor" href="#其他配置项⭐" aria-label="Permalink to &quot;其他配置项⭐&quot;">​</a></h3><h4 id="aof文件重写" tabindex="-1">AOF文件重写 <a class="header-anchor" href="#aof文件重写" aria-label="Permalink to &quot;AOF文件重写&quot;">​</a></h4><blockquote><p>因为是记录命令，AOF文件会比RDB文件大的多。而且AOF会记录对同一个key的多次写操作，但只有最后一次写操作才有意义。通过执行bgrewriteaof命令，可以让AOF文件执行重写功能，用最少的命令达到相同效果。</p></blockquote><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20210725151729118.png" alt="image-20210725151729118"></p><blockquote><p>如图，AOF原本有三个命令，但是<code>set num 123 和 set num 666</code>都是对num的操作，第二次会覆盖第一次的值，因此第一个命令记录下来没有意义。所以重写命令后，AOF文件内容就是：<code>mset name jack num 666</code>，Redis也会在触发阈值时自动去重写AOF文件。阈值也可以在redis.conf中配置：</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202306121452925.png" alt="image-20230612145218817" style="zoom:80%;"><div class="language-properties"><button title="Copy Code" class="copy"></button><span class="lang">properties</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;"># AOF文件比上次文件 增长超过多少百分比则触发重写</span></span>
<span class="line"><span style="color:#A6ACCD;">auto-aof-rewrite-percentage 100</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># AOF文件体积最小多大以上才触发重写，重写触发的最小值：64mb</span></span>
<span class="line"><span style="color:#A6ACCD;">auto-aof-rewrite-min-size 64mb</span></span></code></pre></div><blockquote><p>根据<code>auto-aof-rewrite-min-size</code>和<code>auto-aof-rewrite-percentage</code>参数确定自动触发时机。<code>Redis</code>会记录上次重写时的<code>AOF</code>大小，默认配置是当<code>AOF</code>文件大小是上次<code>rewrite</code>后大小的一倍且文件大于<code>64M</code>时触发。大型互联网公司一般都是<code>3G</code>起步</p></blockquote><h4 id="no-appendfsync-on-rewrite-no" tabindex="-1">no-appendfsync-on-rewrite no <a class="header-anchor" href="#no-appendfsync-on-rewrite-no" aria-label="Permalink to &quot;no-appendfsync-on-rewrite no&quot;">​</a></h4><blockquote><p>重写 AOF 文件期间是否禁止 fsync 操作。如果开启该选项，可以减轻文件重写时 CPU 和磁盘的负载（尤其是磁盘），但是可能会丢失 AOF 重写期间的数据，需要在负载和安全性之间进行平衡。当我们同时执行主进程的<strong>写操作</strong>和子进程的<strong>重写</strong>操作时，两者都会操作磁盘，而重写往往会涉及到大量的磁盘操作，这样就会造成主进程在写aof文件的时候出现阻塞的情形。为了解决这个问题，no-appendfsync-on-rewrite参数出场了。</p></blockquote><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">no</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">appendfsync</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">on</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">rewrite no</span></span></code></pre></div><blockquote><p>如果该参数设置为no，是最安全的方式，不会丢失数据，但是要忍受阻塞的问题；</p></blockquote><blockquote><p>如果设置为yes，这就相当于将appendfsync设置为no，这说明并没有执行磁盘操作，只是写入了缓冲区。因此这样并不会造成阻塞（因为没有竞争磁盘），但是如果这个时候redis挂掉，就会丢失数据。丢失多少数据呢？在linux的操作系统的默认设置下，最多会丢失30s的数据。因此，如果应用系统无法忍受延迟，而可以容忍少量的数据丢失，则设置为yes；如果应用系统无法忍受数据丢失，则设置为no</p></blockquote><h4 id="aof-load-truncated-yes" tabindex="-1">aof-load-truncated yes <a class="header-anchor" href="#aof-load-truncated-yes" aria-label="Permalink to &quot;aof-load-truncated yes&quot;">​</a></h4><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">aof</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">load</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">truncated yes</span></span></code></pre></div><blockquote><p>当AOF文件被截断时，即AOF文件的最后命令不完整，如果此时启动Redis，会将AOF数据加载回内存，此时便会出现问题。</p></blockquote><blockquote><ul><li>yes：加载一个截断的AOF，Redis服务器开始发出日志，通知用户该事件；</li><li>no：服务器将中止并出现错误，拒绝启动。</li></ul></blockquote><h4 id="aof-use-rdb-preamble-yes" tabindex="-1">aof-use-rdb-preamble yes <a class="header-anchor" href="#aof-use-rdb-preamble-yes" aria-label="Permalink to &quot;aof-use-rdb-preamble yes&quot;">​</a></h4><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">aof</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">use</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">rdb</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">preamble yes</span></span></code></pre></div><blockquote><p>在重写AOF文件时，Redis能够在AOF文件中使用RDB前导，以加快重写和恢复速度。启用此选项后，重写的AOF文件由两个不同的节组成：RDB file、AOF tail，加载Redis时，会识别AOF文件以<strong>Redis</strong>字符串开头，并加载带前缀的RDB文件，然后继续加载AOF尾部。</p></blockquote><h2 id="rdb-和-aof-对比" tabindex="-1">RDB 和 AOF 对比 <a class="header-anchor" href="#rdb-和-aof-对比" aria-label="Permalink to &quot;RDB 和 AOF 对比&quot;">​</a></h2><blockquote><p>RDB + AOF：可以将 AOF 和 RDB 组合在同一个 Redis 实例中。如果你愿意的话，可以以速度换取持久化是一种折衷方法。我认为这是设置 Redis 的一种可接受的方式。在重启的情况下，请记住如果两者都启用，Redis 将使用 AOF 来重建数据，因为它是最完整的。</p></blockquote><blockquote><p>RDB和AOF各有自己的优缺点，如果对数据安全性要求较高，在实际开发中往往会<strong>结合</strong>两者来使用</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220317165237120.png" alt="image-20220317165237120" style="zoom:80%;"><blockquote><p>在实际应用时，因为RDB文件只用作后备用途，建议只在slave上持久化RDB文件，而且只需要15分钟备份一次就够了，只保留<code>save 900 1</code>这条规则。</p></blockquote><blockquote><p>如果开启<code>AOF</code>，好处是在最恶劣情况下也只会丢失不超过2秒数据，启动脚本较简单只<code>load</code>自己的<code>AOF</code>文件就可以了。代价一是带来了持续的<code>IO</code>，二是<code>AOF rewrite</code>的最后将<code>rewrite</code>过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。</p></blockquote><blockquote><p>只要硬盘许可，应该尽量减少<code>AOF rewrite</code>的频率，<code>AOF</code>重写的基础大小默认值<code>64M</code>太小了，可以设置到<code>5G</code>以上。默认超过原大小的100%时重写可以改到适当的数值。</p></blockquote><blockquote><p>如果不开启AOF，仅靠Master-Slave Replication实现高可用性也可以。能省掉一大笔IO，也减少了rewrite时带来的系统波动。代价是如果Master/Slave同时倒掉，会丢失十几分钟的数据，启动脚本也要比较两个Master/Slave中的<code>RDB</code>文件，载入较新的那个。</p></blockquote><h2 id="混合持久化" tabindex="-1">混合持久化 <a class="header-anchor" href="#混合持久化" aria-label="Permalink to &quot;混合持久化&quot;">​</a></h2><p>在重启 Redis 服务器时，一般很少使用 RDB 快照文件来恢复内存状态，因为会丢失大量数据。更多的是使用 AOF 文件进行命令重放，但是执行 AOF 命令性能相对 RDB 来说要慢很多。这样在 Redis 数据很大的情况下，启动需要消耗大量的时间。</p><p>鉴于 RDB 快照可能会造成数据丢失，AOF 指令恢复数据慢，Redis 4.0 版本提供了一套基于 AOF-RDB 的混合持久化机制，保留了两种持久化机制的优点。这样重写的 AOF 文件由两部份组成，一部分是 RDB 格式的头部数据，另一部分是 AOF 格式的尾部指令。</p><p>Redis 4.0 版本的混合持久化功能默认是关闭的，通过配置 aof-use-rdb-preamble 为 yes 开启此功能：</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 开启AOF</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">RDB混合持久化机制</span></span>
<span class="line"><span style="color:#A6ACCD;">aof</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">use</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">rdb</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">preamble yes</span></span></code></pre></div><p>查看 Redis 服务器是否开启混合持久化功能：</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">config get aof</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">use</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">rdb</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">preamble</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209142040592.png" alt="image-20220914204017476" style="zoom:80%;"><p>如图所示，将 RDB 数据文件的内容和增量的 AOF 命令文件存在一起。这里的 AOF 命令不再是全量的命令，而是自持久化开始到持久化结束的这段时间服务器进程执行的增量 AOF 命令，通常这部分 AOF 命令很小。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208102128160.png" alt="image-20220810212821988" style="zoom:67%;"><p>在 Redis 服务器重启的时候，可以预先加载 AOF 文件头部全量的 RDB 数据，然后再重放 AOF 文件尾部增量的 AOF 命令</p><h2 id="数据备份与恢复方案" tabindex="-1">数据备份与恢复方案 <a class="header-anchor" href="#数据备份与恢复方案" aria-label="Permalink to &quot;数据备份与恢复方案&quot;">​</a></h2><h3 id="持久化配置" tabindex="-1">持久化配置 <a class="header-anchor" href="#持久化配置" aria-label="Permalink to &quot;持久化配置&quot;">​</a></h3><ul><li>RBD和AOF建议同时打开（Redis4.0之后支持）</li><li>RDB做冷备，AOF做数据恢复（数据更可靠）</li><li>RDB采取默认配置即可，AOF推荐采取everysec每秒策略</li></ul><h3 id="数据备份方案" tabindex="-1">数据备份方案 <a class="header-anchor" href="#数据备份方案" aria-label="Permalink to &quot;数据备份方案&quot;">​</a></h3><h4 id="_1、需求" tabindex="-1">1、需求 <a class="header-anchor" href="#_1、需求" aria-label="Permalink to &quot;1、需求&quot;">​</a></h4><p>我们需要定时备份rdb文件来做冷备，为什么？不是有aof和rbd了吗为什么还要单独写定时任务去备份？因为Redis的aof和rdb是仅仅有一个最新的，比如谁手贱再Redis宕机的时候执行<code>rm -rf aof/rdb</code>了，那不就GG了吗？或者rdb/aof文件损坏了等不可预期的情况。所以我们需要单独备份rdb文件以防万一。</p><p>为什么不定时备份aof而是rdb？定时备份aof没意义呀，<strong>定时</strong>本身就是冷备份，不是实时的，rdb文件又小恢复又快，她哪里不香？</p><h4 id="_2、方案" tabindex="-1">2、方案 <a class="header-anchor" href="#_2、方案" aria-label="Permalink to &quot;2、方案&quot;">​</a></h4><blockquote><ul><li>写crontab定时调度脚本去做数据备份。</li><li>每小时都copy一份redis的rdb文件到一个其他目录中，这个目录里的rdb文件仅仅保留48小时内的。也就是每小时都做备份，保留2天内的rdb，只保留48个rdb。</li><li>每天0点0分copy一份redis的rdb文件到一个其他目录中，这个保留一个月的。也就是按天备份。</li><li>每天半夜找个时间将当前服务上的所有rdb备份都上传到云服务上。</li></ul></blockquote><h4 id="_3、实现⭐⭐" tabindex="-1">3、实现⭐⭐ <a class="header-anchor" href="#_3、实现⭐⭐" aria-label="Permalink to &quot;3、实现⭐⭐&quot;">​</a></h4><h5 id="_1、按小时备份" tabindex="-1">1、按小时备份 <a class="header-anchor" href="#_1、按小时备份" aria-label="Permalink to &quot;1、按小时备份&quot;">​</a></h5><blockquote><p>每小时copy一次备份，删除48小时前的数据。</p></blockquote><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">crontab </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">e</span></span>
<span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 每小时都执行</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">usr</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">local</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">copy</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">redis_rdb_copy_hourly</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">sh脚本</span></span>
<span class="line"><span style="color:#F78C6C;">0</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> sh </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">usr</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">local</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">copy</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">redis_rdb_copy_hourly</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">sh</span></span></code></pre></div><p>redis_rdb_copy_hourly.sh脚本的内容如下：</p><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">#!/bin/sh </span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># +%Y%m%d%k == 年月日时，显示：2022091712</span></span>
<span class="line"><span style="color:#A6ACCD;">cur_date</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">`</span><span style="color:#FFCB6B;">date</span><span style="color:#C3E88D;"> +%Y%m%d%k</span><span style="color:#89DDFF;">`</span></span>
<span class="line"><span style="color:#FFCB6B;">rm</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-rf</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/usr/local/redis/rdb/</span><span style="color:#A6ACCD;">$cur_date</span></span>
<span class="line"><span style="color:#FFCB6B;">mkdir</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/usr/local/redis/rdb/</span><span style="color:#A6ACCD;">$cur_date</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 拷贝rdb到目录</span></span>
<span class="line"><span style="color:#FFCB6B;">cp</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/var/redis/6379/dump.rdb</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/usr/local/redis/rdb/</span><span style="color:#A6ACCD;">$cur_date</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># date -d -48hour +%Y%m%d%k == 48小时前的日期，比如今天2020060214，这个结果就是2020053114</span></span>
<span class="line"><span style="color:#A6ACCD;">del_date</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">`</span><span style="color:#FFCB6B;">date</span><span style="color:#C3E88D;"> -d -48hour +%Y%m%d%k</span><span style="color:#89DDFF;">`</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 删除48小时之前的目录</span></span>
<span class="line"><span style="color:#FFCB6B;">rm</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-rf</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/usr/local/redis/rdb/</span><span style="color:#A6ACCD;">$del_date</span></span></code></pre></div><h5 id="_2、按天备份" tabindex="-1">2、按天备份 <a class="header-anchor" href="#_2、按天备份" aria-label="Permalink to &quot;2、按天备份&quot;">​</a></h5><blockquote><p>每天copy一次备份，删除一个月前的数据。</p></blockquote><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 创建定时任务</span></span>
<span class="line"><span style="color:#A6ACCD;">crontab </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">e</span></span>
<span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 每天</span><span style="color:#F78C6C;">0</span><span style="color:#A6ACCD;">点</span><span style="color:#F78C6C;">0</span><span style="color:#A6ACCD;">分开始执行</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">usr</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">local</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">copy</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">redis_rdb_copy_daily</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">sh脚本</span></span>
<span class="line"><span style="color:#F78C6C;">0</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> sh </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">usr</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">local</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">copy</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">redis_rdb_copy_daily</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">sh</span></span></code></pre></div><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">mkdir </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">usr</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">local</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">copy</span><span style="color:#89DDFF;">/</span></span>
<span class="line"><span style="color:#A6ACCD;">cd </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">usr</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">local</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">copy</span><span style="color:#89DDFF;">/</span></span>
<span class="line"><span style="color:#A6ACCD;">vim  redis_rdb_copy_daily</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">sh</span></span></code></pre></div><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;"># redis_rdb_copy_daily.sh脚本的内容如下：</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">#!/bin/sh </span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 年月日</span></span>
<span class="line"><span style="color:#A6ACCD;">cur_date</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">`</span><span style="color:#FFCB6B;">date</span><span style="color:#C3E88D;"> +%Y%m%d</span><span style="color:#89DDFF;">`</span></span>
<span class="line"><span style="color:#FFCB6B;">rm</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-rf</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/usr/local/redis/rdb/</span><span style="color:#A6ACCD;">$cur_date</span></span>
<span class="line"><span style="color:#FFCB6B;">mkdir</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/usr/local/redis/rdb/</span><span style="color:#A6ACCD;">$cur_date</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 拷贝rdb到目录</span></span>
<span class="line"><span style="color:#FFCB6B;">cp</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/var/redis/6379/dump.rdb</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/usr/local/redis/rdb/</span><span style="color:#A6ACCD;">$cur_date</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 获取一个月前的时间，比如今天是20200602，那么del_date就是20200502</span></span>
<span class="line"><span style="color:#A6ACCD;">del_date</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">`</span><span style="color:#FFCB6B;">date</span><span style="color:#C3E88D;"> -d -1month +%Y%m%d</span><span style="color:#89DDFF;">`</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 删除一个月前的数据</span></span>
<span class="line"><span style="color:#FFCB6B;">rm</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-rf</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/usr/local/redis/rdb/</span><span style="color:#A6ACCD;">$del_date</span></span></code></pre></div><h3 id="数据恢复方案" tabindex="-1">数据恢复方案 <a class="header-anchor" href="#数据恢复方案" aria-label="Permalink to &quot;数据恢复方案&quot;">​</a></h3><h4 id="_1、redis挂了" tabindex="-1">1、redis挂了 <a class="header-anchor" href="#_1、redis挂了" aria-label="Permalink to &quot;1、redis挂了&quot;">​</a></h4><blockquote><p>如果仅仅是redis进程挂了，那么直接重启redis进程即可，Redis会按照持久化配置直接基于持久化文件进行恢复数据。如果有AOF则按照AOF，AOF和RDB一起开的话也走AOF。</p></blockquote><h4 id="_2、持久化文件丢了" tabindex="-1">2、持久化文件丢了 <a class="header-anchor" href="#_2、持久化文件丢了" aria-label="Permalink to &quot;2、持久化文件丢了&quot;">​</a></h4><p>如果持久化文件（rdb/aof）损坏了，或者直接丢失了。那么就要采取我们上面所做的rdb备份来进行恢复了。</p><blockquote><p>不要脑子一热想着很简单，就以为直接把rdb拖过来重启redis进程就完事了，这种想法有很多问题。慢慢道来。</p></blockquote><p>1、问题</p><blockquote><p>问题一：直接把备份的rdb扔到redis持久化目录下然后重启redis不行的原因在于：redis是按照先aof后rdb进行恢复的，所以都是开启aof的，redis启动后会重新生成新的aof文件，里面是空的。所以不会进行任何数据恢复，也就是说虽然你把rdb丢给redis了，但是redis会按照aof来恢复，而aof是redis启动的时候新生成的空文件，所以不会有任何数据进行恢复。</p></blockquote><blockquote><p>问题二：那么我们把rdb文件丢给redis后，先将redis的aof关闭再启动redis进程不就能按照rdb来进行恢复了吗？是这样的，没毛病！但是新的问题来了，我们aof肯定要开的，aof对数据保障更可靠。那什么我们按照rdb文件恢复完后再修改redis配置文件开启aof然后重启redis进程不就得了嘛？大哥…你打开aof然后重启redis，这时候redis又会生成一个空的aof文件，这时候恢复的时候又是啥数据都没了。</p></blockquote><blockquote><p>因为数据是存到内存里，你重启后肯定没了，需要持久化文件来恢复。这时候aof是空的，我恢复个鸡毛啊。</p></blockquote><h4 id="_3、具体方案" tabindex="-1">3、具体方案 <a class="header-anchor" href="#_3、具体方案" aria-label="Permalink to &quot;3、具体方案&quot;">​</a></h4><blockquote><p>可能有人想到方案了，但是耐心看完，看看我的文采如何。</p></blockquote><p>我不管你是持久化文件丢了还是坏了，我都先<code>rm -rf *</code> 给他删了。</p><ul><li>停止redis进程</li><li>删除坏掉的rdb和aof持久化文件。</li><li>修改配置文件关闭redis的aof持久化。</li><li>找到最新备份的rdb文件扔到redis的持久化目录里。（这里最新的肯定是按照小时备份的最后一个）</li><li>启动Redis进程</li><li>执行<code>set appendonly yes</code>动态打开aof持久化。</li></ul><blockquote><p>也就是说打开aof的操作不是修改配置文件然后重启，而是先热修改让他生成aof，这次生成肯定是会带着内存中完整的数据的。然后再修改配置文件重启。</p></blockquote><ul><li>等aof文件生成后再修改redis配置文件打开aof。</li><li>重启redis进程。</li><li>完美收官。</li></ul><h1 id="主从复制" tabindex="-1">主从复制 <a class="header-anchor" href="#主从复制" aria-label="Permalink to &quot;主从复制&quot;">​</a></h1><h2 id="主从复制概述" tabindex="-1">主从复制概述 <a class="header-anchor" href="#主从复制概述" aria-label="Permalink to &quot;主从复制概述&quot;">​</a></h2><h3 id="单点redis问题" tabindex="-1">单点Redis问题 <a class="header-anchor" href="#单点redis问题" aria-label="Permalink to &quot;单点Redis问题&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202306121436559.png" alt="image-20230612143455286" style="zoom:80%;"><blockquote><ul><li><p><strong>数据丢失问题</strong>：<code>Redis是内存存储</code>，<code>服务重启可能会丢失数据</code></p></li><li><p><strong>并发能力问题</strong>：<code>单节点Redis并发能力虽然不错，但也无法满足如618这样的高并发场景</code></p></li><li><p><strong>故障恢复问题</strong>：<code>如果Redis宕机，则服务不可用，需要一种自动的故障恢复手段</code></p></li><li><p><strong>存储能力问题</strong>：<code>Redis基于内存，单节点能存储的数据量难以满足海量数据需求</code></p></li></ul></blockquote><h3 id="主从复制优点" tabindex="-1">主从复制优点 <a class="header-anchor" href="#主从复制优点" aria-label="Permalink to &quot;主从复制优点&quot;">​</a></h3><blockquote><p>单节点Redis的并发能力是有上限的，要进一步提高Redis的并发能力，就需要主从集群，实现读写分离</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209142112213.png" alt="image-20220914211201108" style="zoom:80%;"><blockquote><ul><li><strong>读写分离</strong>：master写、slave读，提高服务器的读写负载能力</li><li><strong>负载均衡</strong>：基于主从结构，配合读写分离，由slave分担master负载</li><li><strong>故障恢复</strong>：当master出现问题时，由slave提供服务，实现快速的故障恢复</li><li><strong>数据冗余</strong>：实现数据热备份，是持久化之外的一种数据冗余方式</li><li><strong>高可用基石</strong>：基于主从复制，构建哨兵模式与集群，实现Redis的高可用方案</li></ul></blockquote><h2 id="一主两从搭建" tabindex="-1">一主两从搭建 <a class="header-anchor" href="#一主两从搭建" aria-label="Permalink to &quot;一主两从搭建&quot;">​</a></h2><blockquote><p>在一台虚拟机开启3个实例，必须准备三份不同的配置文件和目录，配置文件所在目录也就是工作目录</p></blockquote><h3 id="_1-创建目录" tabindex="-1">1）创建目录 <a class="header-anchor" href="#_1-创建目录" aria-label="Permalink to &quot;1）创建目录&quot;">​</a></h3><p>我们创建三个文件夹，名字分别叫7001、7002、7003：</p><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;"># 进入/tmp目录</span></span>
<span class="line"><span style="color:#82AAFF;">cd</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/tmp</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 创建目录</span></span>
<span class="line"><span style="color:#FFCB6B;">mkdir</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7001</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7002</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7003</span></span></code></pre></div><h3 id="_2-关闭aof-启用rdb-可选" tabindex="-1">2）关闭AOF，启用RDB(可选) <a class="header-anchor" href="#_2-关闭aof-启用rdb-可选" aria-label="Permalink to &quot;2）关闭AOF，启用RDB(可选)&quot;">​</a></h3><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">vi </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">etc</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">conf</span></span>
<span class="line"><span style="color:#A6ACCD;">dbfilename dump</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">rdb</span></span>
<span class="line"><span style="color:#A6ACCD;">dir </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">myredis</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">storage</span></span>
<span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 开启RDB</span></span>
<span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> save </span><span style="color:#89DDFF;">&quot;&quot;</span></span>
<span class="line"><span style="color:#A6ACCD;">save </span><span style="color:#F78C6C;">3600</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span></span>
<span class="line"><span style="color:#A6ACCD;">save </span><span style="color:#F78C6C;">300</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">100</span></span>
<span class="line"><span style="color:#A6ACCD;">save </span><span style="color:#F78C6C;">60</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">10000</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 关闭AOF</span></span>
<span class="line"><span style="color:#A6ACCD;">appendonly no</span></span></code></pre></div><h3 id="_3-拷贝配置文件到实例目录" tabindex="-1">3）拷贝配置文件到实例目录 <a class="header-anchor" href="#_3-拷贝配置文件到实例目录" aria-label="Permalink to &quot;3）拷贝配置文件到实例目录&quot;">​</a></h3><p>然后将redis-6.2.4/redis.conf文件拷贝到三个目录中（在/tmp目录执行下列命令）：</p><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;"># 方式一：逐个拷贝</span></span>
<span class="line"><span style="color:#FFCB6B;">cp</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/etc/redis.conf</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7001</span></span>
<span class="line"><span style="color:#FFCB6B;">cp</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/etc/redis.conf</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7002</span></span>
<span class="line"><span style="color:#FFCB6B;">cp</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/etc/redis.conf</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7003</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 方式二：管道组合命令，一键拷贝</span></span>
<span class="line"><span style="color:#82AAFF;">echo</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7001</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7002</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7003</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">|</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">xargs</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-t</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-n</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">cp</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/etc/redis.conf</span></span></code></pre></div><h3 id="_4-修改每个端口、工作目录" tabindex="-1">4）修改每个端口、工作目录 <a class="header-anchor" href="#_4-修改每个端口、工作目录" aria-label="Permalink to &quot;4）修改每个端口、工作目录&quot;">​</a></h3><blockquote><p>修改每个文件夹内的配置文件，将端口分别修改为7001、7002、7003，将rdb文件保存位置都修改为自己所在目录（在/tmp目录执行下列命令）：</p></blockquote><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;"># sed快速修改文档，路径7001/redis.conf，s表示替换,g表示全局6379全部替换</span></span>
<span class="line"><span style="color:#FFCB6B;">sed</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-i</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-e</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">s/6379/7001/g</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-e</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">s/dir .\//dir \/tmp\/7001\//g</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7001</span><span style="color:#C3E88D;">/redis.conf</span></span>
<span class="line"><span style="color:#FFCB6B;">sed</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-i</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-e</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">s/6379/7002/g</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-e</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">s/dir .\//dir \/tmp\/7002\//g</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7002</span><span style="color:#C3E88D;">/redis.conf</span></span>
<span class="line"><span style="color:#FFCB6B;">sed</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-i</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-e</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">s/6379/7003/g</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-e</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">s/dir .\//dir \/tmp\/7003\//g</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7003</span><span style="color:#C3E88D;">/redis.conf</span></span></code></pre></div><h3 id="_5-修改每个实例的声明ip" tabindex="-1">5）修改每个实例的声明IP <a class="header-anchor" href="#_5-修改每个实例的声明ip" aria-label="Permalink to &quot;5）修改每个实例的声明IP&quot;">​</a></h3><blockquote><p>虚拟机本身有多个IP，为了避免将来混乱，我们需要在redis.conf文件中指定每一个实例的绑定ip信息</p></blockquote><div class="language-properties"><button title="Copy Code" class="copy"></button><span class="lang">properties</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;"># redis实例的声明 IP(直接在配置文件中写这条命令也行 )</span></span>
<span class="line"><span style="color:#A6ACCD;">replica-announce-ip 192.168.22.130</span></span></code></pre></div><blockquote><p>每个目录都要改，我们一键完成修改（在/tmp目录执行下列命令）：</p></blockquote><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;"># 逐一执行，1a表示在第一行追加一行内容</span></span>
<span class="line"><span style="color:#FFCB6B;">sed</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-i</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">1a replica-announce-ip 192.168.22.130</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7001</span><span style="color:#C3E88D;">/redis.conf</span></span>
<span class="line"><span style="color:#FFCB6B;">sed</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-i</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">1a replica-announce-ip 192.168.22.130</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7002</span><span style="color:#C3E88D;">/redis.conf</span></span>
<span class="line"><span style="color:#FFCB6B;">sed</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-i</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">1a replica-announce-ip 192.168.22.130</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7003</span><span style="color:#C3E88D;">/redis.conf</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 或者一键修改</span></span>
<span class="line"><span style="color:#82AAFF;">printf</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">%s\n</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7001</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7002</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7003</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">|</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">xargs</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-I</span><span style="color:#A6ACCD;">{} -t sed -i &#39;1a replica-announce-ip 192.168.22.130&#39; {}/redis.conf</span></span></code></pre></div><h3 id="_6-开启主从连接" tabindex="-1">6）开启主从连接 <a class="header-anchor" href="#_6-开启主从连接" aria-label="Permalink to &quot;6）开启主从连接&quot;">​</a></h3><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">server </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">tmp</span><span style="color:#89DDFF;">/</span><span style="color:#F78C6C;">7001</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">conf</span></span>
<span class="line"><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">server </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">tmp</span><span style="color:#89DDFF;">/</span><span style="color:#F78C6C;">7002</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">conf</span></span>
<span class="line"><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">server </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">tmp</span><span style="color:#89DDFF;">/</span><span style="color:#F78C6C;">7003</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">conf</span></span></code></pre></div><p>开启主节点</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">cli </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p </span><span style="color:#F78C6C;">7001</span></span></code></pre></div><p>开启两个从节点连接主节点</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 开启</span><span style="color:#F78C6C;">7002</span></span>
<span class="line"><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">cli </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p </span><span style="color:#F78C6C;">7002</span></span>
<span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 执行slaveof</span></span>
<span class="line"><span style="color:#A6ACCD;">slaveof </span><span style="color:#F78C6C;">192.168.22.130</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7001</span></span>
<span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 开启</span><span style="color:#F78C6C;">7003</span></span>
<span class="line"><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">cli </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p </span><span style="color:#F78C6C;">7003</span></span>
<span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 执行slaveof</span></span>
<span class="line"><span style="color:#A6ACCD;">slaveof </span><span style="color:#F78C6C;">192.168.22.130</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7001</span></span></code></pre></div><p>进入7001查看连接是否成功</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">info replication</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041137099.png" alt="image-20220504113756968" style="zoom:67%;"><h3 id="_7-测试使用" tabindex="-1">7）测试使用 <a class="header-anchor" href="#_7-测试使用" aria-label="Permalink to &quot;7）测试使用&quot;">​</a></h3><p>执行下列操作以测试：</p><ul><li><p>利用redis-cli连接7001，执行<code>set num 123</code></p></li><li><p>利用redis-cli连接7002，执行<code>get num</code>，再执行<code>set num 666</code></p></li><li><p>利用redis-cli连接7003，执行<code>get num</code>，再执行<code>set num 888</code></p></li></ul><p>可以发现，只有在7001这个master节点上可以执行写操作，7002和7003这两个slave节点只能执行读操作。</p><h2 id="主从同步优化" tabindex="-1">主从同步优化 <a class="header-anchor" href="#主从同步优化" aria-label="Permalink to &quot;主从同步优化&quot;">​</a></h2><p>主从同步可以保证主从数据的一致性，非常重要。可以从以下几个方面来优化Redis主从集群：</p><blockquote><ul><li>在master中配置repl-diskless-sync yes启用无磁盘复制，避免全量同步时的磁盘IO。</li><li>Redis单节点上的内存占用不要太大，减少RDB导致的过多磁盘IO</li><li>适当提高repl_baklog的大小，发现slave宕机时尽快实现故障恢复，尽可能避免全量同步</li><li>限制一个master上的slave节点数量，如果实在是太多slave，则可以采用<strong>主-从-从</strong>链式结构</li></ul></blockquote><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20210725154405899.png" alt="image-20210725154405899"></p><h2 id="哨兵模式⭐" tabindex="-1">哨兵模式⭐ <a class="header-anchor" href="#哨兵模式⭐" aria-label="Permalink to &quot;哨兵模式⭐&quot;">​</a></h2><h3 id="哨兵的结构和作用" tabindex="-1">哨兵的结构和作用 <a class="header-anchor" href="#哨兵的结构和作用" aria-label="Permalink to &quot;哨兵的结构和作用&quot;">​</a></h3><blockquote><p>Sentinel 是一个分布式系统。与所有分布式系统一样，Sentinel 有几个优点和缺点。Sentinel 的设计方式是，<strong>一组哨兵进程协同工作以协调状态，从而为 Redis 提供高可用性</strong>。毕竟，你不希望保护你免受故障影响的系统有自己的单点故障。</p></blockquote><blockquote><p>Sentinel 负责一些事情。首先，它确保当前的主实例和从实例正常运行并做出响应。这是必要的，因为哨兵（与其他哨兵进程）可以在主节点和/或从节点丢失的情况下发出警报并采取行动。其次，它在服务发现中发挥作用，就像其他系统中的 Zookeeper 和 Consul 一样。所以当一个新的客户端尝试向 Redis 写东西时，Sentinel 会告诉客户端当前的主实例是什么。因此，哨兵不断监控可用性并将该信息发送给客户端，以便他们能够在他们确实进行故障转移时对其做出反应。</p></blockquote><blockquote><ul><li><strong>监控</strong>：Sentinel 会不断检查您的master和slave是否按预期工作</li><li><strong>配置管理</strong>——Sentinel 节点还充当当前主 Redis 实例的发现服务。</li><li><strong>自动故障恢复</strong>：如果master故障，Sentinel会将一个slave提升为master。</li><li><strong>通知</strong>：Sentinel充当Redis客户端的服务发现，故障转移时，会将最新信息推送给Redis的客户端</li></ul></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041042508.png" alt="image-20220504104258420" style="zoom:80%;"><h3 id="搭建哨兵集群⭐" tabindex="-1">搭建哨兵集群⭐ <a class="header-anchor" href="#搭建哨兵集群⭐" aria-label="Permalink to &quot;搭建哨兵集群⭐&quot;">​</a></h3><p>这里我们搭建一个三节点形成的Sentinel集群，来监管之前的Redis主从集群。如图：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041300241.png" alt="image-20220504130043145" style="zoom:50%;"><p>三个sentinel实例信息如下：</p><table><thead><tr><th>节点</th><th style="text-align:center;">IP</th><th style="text-align:center;">PORT</th></tr></thead><tbody><tr><td>s1</td><td style="text-align:center;">192.168.22.130</td><td style="text-align:center;">27001</td></tr><tr><td>s2</td><td style="text-align:center;">192.168.22.130</td><td style="text-align:center;">27002</td></tr><tr><td>s3</td><td style="text-align:center;">192.168.22.130</td><td style="text-align:center;">27003</td></tr></tbody></table><h4 id="准备实例和配置" tabindex="-1">准备实例和配置 <a class="header-anchor" href="#准备实例和配置" aria-label="Permalink to &quot;准备实例和配置&quot;">​</a></h4><blockquote><p>要在同一台虚拟机开启3个实例，必须准备三份不同的配置文件和目录，配置文件所在目录也就是工作目录。我们创建三个文件夹，名字分别叫s1、s2、s3：</p></blockquote><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;"># 进入/tmp目录</span></span>
<span class="line"><span style="color:#82AAFF;">cd</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/tmp</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 创建目录</span></span>
<span class="line"><span style="color:#FFCB6B;">mkdir</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">s1</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">s2</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">s3</span></span></code></pre></div><blockquote><p>然后我们在s1目录创建一个sentinel.conf文件，添加下面的内容：</p></blockquote><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 当前sentinel实例的端口</span></span>
<span class="line"><span style="color:#A6ACCD;">port </span><span style="color:#F78C6C;">27001</span></span>
<span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> sentinel实例的IP地址</span></span>
<span class="line"><span style="color:#A6ACCD;">sentinel announce</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">ip </span><span style="color:#F78C6C;">192.168.22.130</span></span>
<span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> mymaster主节点名称，自定义，主节点IP，端口号</span></span>
<span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">2</span><span style="color:#A6ACCD;">选举master时的quorum值，表示一半以上，超过它则进行选取，因为现在有</span><span style="color:#F78C6C;">3</span><span style="color:#A6ACCD;">台，所以设置</span><span style="color:#F78C6C;">2</span></span>
<span class="line"><span style="color:#A6ACCD;">sentinel monitor mymaster </span><span style="color:#F78C6C;">192.168.22.130</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7001</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">2</span></span>
<span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> slave和master的超时时间</span></span>
<span class="line"><span style="color:#A6ACCD;">sentinel down</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">after</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">milliseconds mymaster </span><span style="color:#F78C6C;">5000</span></span>
<span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> slave故障恢复的超时时间</span></span>
<span class="line"><span style="color:#A6ACCD;">sentinel failover</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">timeout mymaster </span><span style="color:#F78C6C;">60000</span></span>
<span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 工作目录</span></span>
<span class="line"><span style="color:#A6ACCD;">dir </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">/tmp/s1</span><span style="color:#89DDFF;">&quot;</span></span></code></pre></div><blockquote><p>然后将s1/sentinel.conf文件拷贝到s2、s3两个目录中（在/tmp目录执行下列命令）：</p></blockquote><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;"># 方式一：逐个拷贝</span></span>
<span class="line"><span style="color:#FFCB6B;">cp</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">s1/sentinel.conf</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">s2</span></span>
<span class="line"><span style="color:#FFCB6B;">cp</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">s1/sentinel.conf</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">s3</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 方式二：管道组合命令，一键拷贝</span></span>
<span class="line"><span style="color:#82AAFF;">echo</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">s2</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">s3</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">|</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">xargs</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-t</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-n</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">cp</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">s1/sentinel.conf</span></span></code></pre></div><blockquote><p>只需要改端口和目录，修改s2、s3两个文件夹内的配置文件，将端口分别修改为27002、27003：</p></blockquote><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#FFCB6B;">sed</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-i</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-e</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">s/27001/27002/g</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-e</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">s/s1/s2/g</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">s2/sentinel.conf</span></span>
<span class="line"><span style="color:#FFCB6B;">sed</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-i</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-e</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">s/27001/27003/g</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-e</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">s/s1/s3/g</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">s3/sentinel.conf</span></span></code></pre></div><h4 id="启动哨兵集群" tabindex="-1">启动哨兵集群 <a class="header-anchor" href="#启动哨兵集群" aria-label="Permalink to &quot;启动哨兵集群&quot;">​</a></h4><p>为了方便查看日志，我们打开3个ssh窗口，分别启动3个redis实例，启动命令：</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 第</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">个</span></span>
<span class="line"><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">sentinel s1</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">sentinel</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">conf</span></span>
<span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 第</span><span style="color:#F78C6C;">2</span><span style="color:#A6ACCD;">个</span></span>
<span class="line"><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">sentinel s2</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">sentinel</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">conf</span></span>
<span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 第</span><span style="color:#F78C6C;">3</span><span style="color:#A6ACCD;">个</span></span>
<span class="line"><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">sentinel s3</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">sentinel</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">conf</span></span></code></pre></div><p>启动后：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041301993.png" alt="image-20210701220714104" style="zoom:80%;"><h4 id="测试哨兵集群" tabindex="-1">测试哨兵集群 <a class="header-anchor" href="#测试哨兵集群" aria-label="Permalink to &quot;测试哨兵集群&quot;">​</a></h4><blockquote><p>尝试让master节点7001宕机，查看sentinel日志：</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041301998.png" alt="image-20210701222857997" style="zoom:80%;"><blockquote><p>查看7003的日志：</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041301997.png" alt="image-20210701223025709" style="zoom:67%;"><blockquote><p>查看7002的日志：</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041301999.png" alt="image-20210701223131264" style="zoom:67%;"><h3 id="哨兵工作原理" tabindex="-1">哨兵工作原理 <a class="header-anchor" href="#哨兵工作原理" aria-label="Permalink to &quot;哨兵工作原理&quot;">​</a></h3><h4 id="服务状态监控" tabindex="-1">服务状态监控 <a class="header-anchor" href="#服务状态监控" aria-label="Permalink to &quot;服务状态监控&quot;">​</a></h4><blockquote><p>判断Redis实例是否健康：Sentinel基于<strong>心跳机制监测</strong>服务状态，每秒向集群的每个实例发ping命令</p></blockquote><blockquote><ul><li><p>主观下线：如果某sentinel节点发现某实例<strong>未在规定时间响应</strong>，则认为该实例<strong>主观下线</strong>。</p></li><li><p>客观下线：<strong>若超过指定数量（quorum）的sentinel都认为该实例主观下线</strong>，则该实例<strong>客观下线</strong>。quorum值最好超过Sentinel实例数量的一半</p></li></ul></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041043780.png" alt="image-20220504104346706" style="zoom:67%;"><h4 id="选举新的master" tabindex="-1">选举新的master <a class="header-anchor" href="#选举新的master" aria-label="Permalink to &quot;选举新的master&quot;">​</a></h4><p>一旦发现master故障，sentinel需要在salve中选择一个作为新的master，选择依据是这样的</p><blockquote><ul><li>首先会判断slave节点与master节点断开时间长短，如果超过指定值（down-after-milliseconds * 10）则会排除该slave节点</li><li>然后判断slave节点的slave-priority值，越小优先级越高，如果是0则永不参与选举</li><li>如果slave-prority一样，则判断slave节点的offset值，越大说明数据越新，优先级越高</li><li>最后是判断slave节点的运行id大小，越小优先级越高。</li></ul></blockquote><h4 id="如何实现故障转移" tabindex="-1">如何实现故障转移 <a class="header-anchor" href="#如何实现故障转移" aria-label="Permalink to &quot;如何实现故障转移&quot;">​</a></h4><p>当选中了其中一个slave为新的master后（例如slave1），故障的转移的步骤如下：</p><blockquote><ul><li>sentinel给备选的slave1节点发送slaveof no one命令，让该节点成为master</li><li>sentinel给所有其它slave发送slaveof 192.168.150.101 7002 命令，让这些slave成为新master的从节点，开始从新的master上同步数据。</li><li>最后，sentinel将故障节点标记为slave，当故障节点恢复后会自动成为新的master的slave节点</li></ul></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041250007.png" alt="image-20220504125057925" style="zoom:67%;"><h2 id="主从复制原理" tabindex="-1">主从复制原理 <a class="header-anchor" href="#主从复制原理" aria-label="Permalink to &quot;主从复制原理&quot;">​</a></h2><h3 id="全量同步" tabindex="-1">全量同步 <a class="header-anchor" href="#全量同步" aria-label="Permalink to &quot;全量同步&quot;">​</a></h3><blockquote><p>用于初次复制或其它无法进行部分复制的情况，将主节点中的所有数据都发送给从节点。当数据量过大的时候，会造成很大的网络开销。</p></blockquote><p>什么时候执行全量同步？</p><blockquote><ul><li>slave节点第一次连接master节点时</li><li>slave节点断开时间太久，repl_baklog中的offset已经被覆盖时</li></ul></blockquote><p>简述全量同步的流程？</p><blockquote><ul><li>slave节点请求增量同步</li><li>master节点判断replid，发现不一致，拒绝增量同步</li><li>master将完整内存数据生成RDB，发送RDB到slave</li><li>slave清空本地数据，加载master的RDB</li><li>master将RDB期间的命令记录在repl_baklog，并持续将log中的命令发送给slave</li><li>slave执行接收到的命令，保持与master之间的同步</li></ul></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209142125105.png" alt="image-20220914212506004" style="zoom:80%;"><blockquote><p>master如何判断slave是不是第一次来同步数据？这里会用到两个很重要的概念：</p></blockquote><blockquote><p><strong>Replication Id</strong>：简称replid，是数据集的标记，id一致则说明是同一数据集。每一个master都有唯一的replid，slave则会继承master节点的replid</p></blockquote><blockquote><p><strong>offset</strong>：偏移量，随着记录在repl_baklog中的数据增多而逐渐增大。slave完成同步时也会记录当前同步的offset。如果slave的offset小于master的offset，说明slave数据落后于master，需要更新。因此slave做数据同步，必须向master声明自己的replication id 和offset，master才可以判断到底需要同步哪些数据</p></blockquote><h3 id="增量同步" tabindex="-1">增量同步 <a class="header-anchor" href="#增量同步" aria-label="Permalink to &quot;增量同步&quot;">​</a></h3><blockquote><p>用于处理在主从复制中因网络闪退等原因造成数据丢失场景，当从节点再次连上主节点，如果条件允许，主节点会补发丢失数据给从节点，因为补发的数据远远小于全量数据，可以有效避免全量复制的过高开销。但需要注意，如果网络中断时间过长，造成主节点没有能够完整地保存中断期间执行的写命令，则无法进行部分复制，仍使用全量复制。</p></blockquote><blockquote><p>主从第一次同步是<strong>全量同步</strong>，但如果slave重启后同步，则执行<strong>增量同步</strong></p></blockquote><blockquote><p>什么时候执行增量同步？slave节点断开又恢复，并且在repl_baklog中能找到offset时</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041245051.png" alt="image-20220504124526950" style="zoom:67%;"><blockquote><p>注意：repl_baklog大小有上限，写满后会覆盖最早的数据。如果slave断开时间过久，导致尚未备份的数据被覆盖，则无法基于log做增量同步，只能再次全量同步。</p></blockquote><p>简述全量同步和增量同步区别？</p><blockquote><p>全量同步：master将完整内存数据生成RDB，发RDB到slave。后续命令记录repl_baklog，逐个发给slave</p><p>增量同步：slave提交自己的offset到master，master获取repl_baklog中从offset之后的命令给slave</p></blockquote><p>什么时候执行全量同步？</p><blockquote><p><strong>slave节点第一次连接master节点时</strong></p><p><strong>slave节点断开时间太久，repl_baklog中的offset已经被覆盖时</strong></p></blockquote><p>什么时候执行增量同步？</p><blockquote><p><strong>slave节点断开又恢复，并且在repl_baklog中能找到offset时</strong></p></blockquote><h3 id="脑裂问题" tabindex="-1">脑裂问题 <a class="header-anchor" href="#脑裂问题" aria-label="Permalink to &quot;脑裂问题&quot;">​</a></h3><blockquote><p>脑裂是指因为网络原因，导致master节点、slave节点 和 sentinel集群<code>处于不同的网络分区</code>，此时因为sentinel集群<strong>无法感知</strong>到master的存在，所以将slave节点提升为master节点 此时存在两个不同的master节点就像一个大脑分裂成了两个。其实在<code>Hadoop</code> 、<code>Spark</code>集群中都会出现这样的情况，只是解决方法不同而已(用ZK配合强制杀死)。</p></blockquote><blockquote><p>集群脑裂问题中，如果客户端还在基于原来的master节点继续写入数据那么新的master节点将无法同步这些数据，当网络问题解决后sentinel集群将原先的master节点降为slave节点，此时再从新的master中同步数据将造成大量的数据丢失。Redis处理方案是redis的配置文件中存在两个参数</p></blockquote><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">min</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">replicas</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">to</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">write </span><span style="color:#F78C6C;">3</span><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 表示连接到master的最少slave数量</span></span>
<span class="line"><span style="color:#A6ACCD;">min</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">replicas</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">max</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">lag </span><span style="color:#F78C6C;">10</span><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 表示slave连接到master的最大延迟时间</span></span></code></pre></div><blockquote><p>如果连接到master的slave数量 &lt; 第一个参数 且 ping的延迟时间 &lt;= 第二个参数那么master就会拒绝写请求，配置了这两个参数后如果发生了集群脑裂则原先的master节点接收到客户端的写入请求会拒绝就可以减少数据同步之后的数据丢失。</p></blockquote><h1 id="分片集群" tabindex="-1">分片集群 <a class="header-anchor" href="#分片集群" aria-label="Permalink to &quot;分片集群&quot;">​</a></h1><h2 id="集群概述" tabindex="-1">集群概述 <a class="header-anchor" href="#集群概述" aria-label="Permalink to &quot;集群概述&quot;">​</a></h2><h3 id="为什么需要集群" tabindex="-1">为什么需要集群 <a class="header-anchor" href="#为什么需要集群" aria-label="Permalink to &quot;为什么需要集群&quot;">​</a></h3><p>主从和哨兵可以解决高可用、高并发读的问题。但是依然有两个问题没有解决：</p><blockquote><p><strong>海量数据存储问题、高并发写的问题</strong></p></blockquote><p>使用分片集群可以解决上述问题，分片集群特征：</p><blockquote><p><strong>高可用性：</strong> Redis 在集群模式下每个 Master 都是主从复制模式，其 Master 节点上的数据会实时同步到 Slave 节点上，当 Master 节点不可用时，对应的 Slave 节点身份会更改为 Master 节点，保证集群可用性</p></blockquote><blockquote><p><strong>数据横向扩展：</strong> Redis 是一个内存数据库，所有数据都存在内存中，在单节点中所在服务器能给与的内存是有一定限制。当数据量达到一定程度后，内存将不足以支撑这么多的数据存储，这时候需要将数据进行分片存储，而 Redis 集群模式就是将数据分片存储，非常方便横向扩展。</p></blockquote><blockquote><ul><li>集群中有多个master，每个master保存不同数据，分摊压力</li><li>每个master都可以有多个slave节点，实现扩容，无中心配置相对简单</li><li>master之间通过ping监测彼此健康状态</li><li>客户端请求可以访问集群任意节点，最终都会被转发到正确节点</li></ul></blockquote><h3 id="集群带来的问题" tabindex="-1">集群带来的问题 <a class="header-anchor" href="#集群带来的问题" aria-label="Permalink to &quot;集群带来的问题&quot;">​</a></h3><blockquote><ul><li><p>多键操作是不被支持的</p></li><li><p>多键的Redis事务是不被支持的。lua脚本不被支持</p></li><li><p>由于集群方案出现较晚，很多公司已经采用了其他的集群方案，而代理或者客户端分片的方案想要迁移至redis cluster，需要整体迁移而不是逐步过渡，复杂度较大。</p></li><li><p>复制结构只支持单层结构，不支持树型结构。</p></li><li><p>不支持多数据库，只能使用 0 数据库，执行 select 0 命令；</p></li><li><p>键是数据分区的最小粒度，不能将一个很大的键值对映射到不同的节点；</p></li><li><p>键事务支持有限，当多个键分布在不同节点时无法使用事务，同一节点才能支持事务；</p></li><li><p>键的批量操作支持有限，比如 mset, mget 命令，如果多个键映射在不同的槽中，就不能正常用了</p></li></ul></blockquote><h2 id="主要概念" tabindex="-1">主要概念 <a class="header-anchor" href="#主要概念" aria-label="Permalink to &quot;主要概念&quot;">​</a></h2><h3 id="集群的数据分片" tabindex="-1">集群的数据分片 <a class="header-anchor" href="#集群的数据分片" aria-label="Permalink to &quot;集群的数据分片&quot;">​</a></h3><p>Redis 集群没有使用一致性 Hash, 而是引入了”哈希槽”的概念。Redis 集群有 16384 个哈希槽，每个 key 通过 CRC16 校验后对 16384 取模来决定放置哪个槽，集群的每个节点负责一部分 hash 槽。</p><p>举个例子，比如当前集群有3个节点，那么:</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208082201832.png" alt="image-20220808220103736" style="zoom:67%;"><ul><li>节点 A 包含 0 到 5460 号哈希槽；</li><li>节点 B 包含 5461 到 10922 号哈希槽；</li><li>节点 C 包含 10923 到 16383 号哈希槽；</li></ul><p>这种结构很容易”添加”或者”删除”节点. 比如如果我想新添加个节点 D，我需要从节点 A, B, C 中得部分槽转移到节点 D 上， 如果我想移除节点 A，则需要将 A 中的槽移到 B 和 C 节点上，然后将没有任何槽的 A 节点从集群中移除即可。由于从一个节点将哈希槽移动到另一个节点并不会停止服务，所以无论添加删除或者改变某个节点的哈希槽的数量都不会造成集群不可用的状态。</p><p>Redis 支持多个 key 操作，只要这些 key 在一个单个命令中执行（或者一个事务，或者 Lua 脚本执行），那么它们就属于相同的 Hash 槽。你也可以用 hash tags 命令强制多个 key 都在相同的 hash 槽中。</p><p>一个 Redis 集群包含 16384 个插槽（hash slot）， 数据库中的每个键都属于这 16384 个插槽的其中一个，</p><p>集群使用公式 CRC16(key) % 16384 来计算键 key 属于哪个槽， 其中 CRC16(key) 语句用于计算键 key 的 CRC16 校验和</p><p>集群中的每个节点负责处理一部分插槽。 举个例子， 如果一个集群可以有主节点， 其中：</p><h3 id="如何分配这六个节点" tabindex="-1">如何分配这六个节点 <a class="header-anchor" href="#如何分配这六个节点" aria-label="Permalink to &quot;如何分配这六个节点&quot;">​</a></h3><p>一个集群至少要有三个主节点。</p><p>选项 --cluster-replicas 1 表示我们希望为集群中的每个主节点创建一个从节点。</p><p>分配原则尽量保证每个主数据库运行在不同的IP地址，每个从库和主库不在一个IP地址上。</p><h3 id="集群间通信机制" tabindex="-1">集群间通信机制 <a class="header-anchor" href="#集群间通信机制" aria-label="Permalink to &quot;集群间通信机制&quot;">​</a></h3><p>在 Redis 集群中，数据节点提供两个 TCP 端口，在配置防火墙时需要同时开启下面两类端口：</p><ul><li><strong>普通端口：</strong> 即客户端访问端口，如默认的 6379；</li><li><strong>集群端口：</strong> 普通端口号加 10000，如 6379 的集群端口为 16379，用于集群节点之间的通讯；</li></ul><p>集群的节点之间通讯采用 Gossip 协议，节点根据固定频率(每秒10次)定时任务进行判断，当集群状态发生变化，如增删节点、槽状态变更时，会通过节点间通讯同步集群状态，使集群收敛。集群间发送的 Gossip 消息有下面五种消息类型：</p><ul><li><strong>MEET：</strong> 在节点握手阶段，对新加入的节点发送 meet 消息，请求新节点加入当前集群，新节点收到消息会回复 pong 消息；</li><li><strong>PING：</strong> 节点之间互相发送 ping 消息，收到消息的会回复 pong 消息。ping 消息内容包含本节点和其他节点的状态信息，以此达到状态同步；</li><li><strong>PONG：</strong> pong 消息包含自身的状态数据，在接收到 ping 或 meet 消息时会回复 pong 消息，也会主动向集群广播 pong 消息；</li><li><strong>FAIL：</strong> 当一个主节点判断另一个主节点进入 fail 状态时，会向集群广播这个消息，接收到的节点会保存该消息并对该 fail 节点做状态判断；</li><li><strong>PUBLISH：</strong> 当节点收到 publish 命令时，会先执行命令，然后向集群广播 publish 消息，接收到消息的节点也会执行 publish 命令；</li></ul><h3 id="集群失败状态" tabindex="-1">集群失败状态 <a class="header-anchor" href="#集群失败状态" aria-label="Permalink to &quot;集群失败状态&quot;">​</a></h3><p>在 Redis 集群模式下也不可能百分百保证集群可用性，当发生不可预知的事件导致 Redis 集群将进入失败状态，在这种状态下 Redis 集群将不能正常提供服务。其中进入失败状态的条件主要为：</p><ul><li>① 全部节点都宕机，集群将进入 fail 状态；</li><li>② 半数以上主节点不可用，集群将进入 fail 状态；</li><li>③ 任意主节点挂掉，且该主节点没有对应的从节点或者从节点也全部挂掉，集群将进入 fail 状态；</li></ul><h3 id="集群重新分片机制" tabindex="-1">集群重新分片机制 <a class="header-anchor" href="#集群重新分片机制" aria-label="Permalink to &quot;集群重新分片机制&quot;">​</a></h3><p>Redis 集群重新分片（新增/移除节点）机制：</p><ul><li>新增节点：别的节点上的槽分一些出来给新的节点</li><li>删除节点：删除节点的槽分给别的节点</li></ul><p>但这些操作是需要手动完成的，可以在不停止服务器的情况下执行。</p><h2 id="搭建分片集群" tabindex="-1">搭建分片集群 <a class="header-anchor" href="#搭建分片集群" aria-label="Permalink to &quot;搭建分片集群&quot;">​</a></h2><p>这里我们会在同一台虚拟机中开启6个redis实例，模拟分片集群，信息如下：</p><table><thead><tr><th style="text-align:center;">IP</th><th style="text-align:center;">PORT</th><th style="text-align:center;">角色</th></tr></thead><tbody><tr><td style="text-align:center;">192.168.22.145</td><td style="text-align:center;">7001</td><td style="text-align:center;">master</td></tr><tr><td style="text-align:center;">192.168.22.145</td><td style="text-align:center;">7002</td><td style="text-align:center;">master</td></tr><tr><td style="text-align:center;">192.168.22.145</td><td style="text-align:center;">7003</td><td style="text-align:center;">master</td></tr><tr><td style="text-align:center;">192.168.22.145</td><td style="text-align:center;">8001</td><td style="text-align:center;">slave</td></tr><tr><td style="text-align:center;">192.168.22.145</td><td style="text-align:center;">8002</td><td style="text-align:center;">slave</td></tr><tr><td style="text-align:center;">192.168.22.145</td><td style="text-align:center;">8003</td><td style="text-align:center;">slave</td></tr></tbody></table><h3 id="准备实例和配置-1" tabindex="-1">准备实例和配置 <a class="header-anchor" href="#准备实例和配置-1" aria-label="Permalink to &quot;准备实例和配置&quot;">​</a></h3><p>删除之前的7001、7002、7003这几个目录，重新创建出7001、7002、7003、8001、8002、8003目录：</p><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;"># 进入/tmp目录</span></span>
<span class="line"><span style="color:#82AAFF;">cd</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/tmp</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 删除旧的，避免配置干扰</span></span>
<span class="line"><span style="color:#FFCB6B;">rm</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-rf</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7001</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7002</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7003</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 创建目录</span></span>
<span class="line"><span style="color:#FFCB6B;">mkdir</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7001</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7002</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7003</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">8001</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">8002</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">8003</span></span></code></pre></div><p>在/tmp下准备一个新的redis.conf文件，内容如下：</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">vi </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">tmp</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">conf</span></span></code></pre></div><div class="language-ini"><button title="Copy Code" class="copy"></button><span class="lang">ini</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">port 6379</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 开启集群功能</span></span>
<span class="line"><span style="color:#A6ACCD;">cluster-enabled yes</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 集群的配置文件名称，不需要我们创建，由redis自己维护，我们只能指定其存储的位置</span></span>
<span class="line"><span style="color:#A6ACCD;">cluster-config-file /tmp/6379/nodes.conf</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 设置Redis群集节点的通信的超时时间；节点心跳失败的超时时间</span></span>
<span class="line"><span style="color:#A6ACCD;">cluster-node-timeout 5000</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 持久化文件存放目录</span></span>
<span class="line"><span style="color:#A6ACCD;">dir /tmp/6379</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 绑定地址</span></span>
<span class="line"><span style="color:#A6ACCD;">bind 0.0.0.0</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 让redis后台运行</span></span>
<span class="line"><span style="color:#A6ACCD;">daemonize yes</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 注册的实例ip</span></span>
<span class="line"><span style="color:#A6ACCD;">replica-announce-ip 192.168.22.145</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 保护模式</span></span>
<span class="line"><span style="color:#A6ACCD;">protected-mode no</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 数据库数量</span></span>
<span class="line"><span style="color:#A6ACCD;">databases 1</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 日志</span></span>
<span class="line"><span style="color:#A6ACCD;">logfile /tmp/6379/run.log</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 主节点需要的最小从节点数，只有达到这个数，主节点失败时，它从节点才会进行迁移</span></span>
<span class="line"><span style="color:#A6ACCD;">cluster-migration-barrier 1</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 0：则无论从节点与主节点失联多久，从节点都会尝试升级成主节点。</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 正数：则 cluster-node-timeout、cluster-slave-validity-factor得到的时间，是从节点与主节点失联后，此从节点数据有效的最长时间，超过这个时间，从节点不会启动故障迁移。假设cluster-node-timeout=5，cluster-slave-validity-factor=10，则如果从节点跟主节点失联超过50秒，此从节点不能成为主节点。</span></span>
<span class="line"><span style="color:#A6ACCD;">cluster-replica-validity-factor 10</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 设置集群可用性</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># yes：表示当负责一个插槽的主库下线，且没有相应的从库进行故障恢复时，集群不可用</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># no：表示当负责一个插槽的主库下线且没有相应的从库进行故障恢复时，集群仍然可用</span></span>
<span class="line"><span style="color:#A6ACCD;">cluster-require-full-coverage yes</span></span></code></pre></div><p>将这个文件拷贝到每个目录下：</p><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;"># 进入/tmp目录</span></span>
<span class="line"><span style="color:#82AAFF;">cd</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/tmp</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 执行拷贝</span></span>
<span class="line"><span style="color:#82AAFF;">echo</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7001</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7002</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7003</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">8001</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">8002</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">8003</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">|</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">xargs</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-t</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-n</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">cp</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">redis.conf</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209171200274.png" alt="image-20220917120025086" style="zoom:80%;"><p>修改每个目录下的redis.conf，将其中的6379修改为与所在目录一致：</p><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;"># 进入/tmp目录</span></span>
<span class="line"><span style="color:#82AAFF;">cd</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/tmp</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 修改配置文件</span></span>
<span class="line"><span style="color:#82AAFF;">printf</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">%s\n</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7001</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7002</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7003</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">8001</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">8002</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">8003</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">|</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">xargs</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-I</span><span style="color:#A6ACCD;">{} -t sed -i &#39;s/6379/{}/g&#39; {}/redis.conf</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209171200300.png" alt="image-20220917120058104" style="zoom:80%;"><h3 id="启动每个节点" tabindex="-1">启动每个节点 <a class="header-anchor" href="#启动每个节点" aria-label="Permalink to &quot;启动每个节点&quot;">​</a></h3><p>因为已经配置了后台启动模式，所以可以直接启动服务：</p><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;"># 进入/tmp目录</span></span>
<span class="line"><span style="color:#82AAFF;">cd</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/tmp</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 一键启动所有服务</span></span>
<span class="line"><span style="color:#82AAFF;">printf</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">%s\n</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7001</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7002</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7003</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">8001</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">8002</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">8003</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">|</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">xargs</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-I</span><span style="color:#A6ACCD;">{} -t redis-server {}/redis.conf</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209171201425.png" alt="image-20220917120137266" style="zoom:80%;"><p>通过ps查看状态：</p><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#FFCB6B;">ps</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-ef</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">|</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">grep</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">redis</span></span></code></pre></div><p>发现服务都已经正常启动：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041412850.png" alt="image-20220504141231750" style="zoom:80%;"><h3 id="关闭节点-可选" tabindex="-1">关闭节点(可选) <a class="header-anchor" href="#关闭节点-可选" aria-label="Permalink to &quot;关闭节点(可选)&quot;">​</a></h3><p>如果要关闭所有进程，可以执行命令：</p><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#FFCB6B;">ps</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-ef</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">|</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">grep</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">redis</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">|</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">awk</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">{print $2}</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">|</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">xargs</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">kill</span></span></code></pre></div><p>或者（推荐这种方式）：</p><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#82AAFF;">printf</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">%s\n</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7001</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7002</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7003</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">8001</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">8002</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">8003</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">|</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">xargs</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-I</span><span style="color:#A6ACCD;">{} -t redis-cli -p {} shutdown</span></span></code></pre></div><h3 id="创建集群" tabindex="-1">创建集群 <a class="header-anchor" href="#创建集群" aria-label="Permalink to &quot;创建集群&quot;">​</a></h3><blockquote><p>虽然服务启动了，但是目前每个服务之间都是独立的，没有任何关联。我们需要执行命令来创建集群，在Redis5.0之前创建集群比较麻烦，5.0之后集群管理命令都集成到了redis-cli中。</p></blockquote><blockquote><p>1）Redis5.0之前：Redis5.0之前集群命令都是用redis安装包下的src/redis-trib.rb来实现的。因为redis-trib.rb是有ruby语言编写的所以需要安装ruby环境。</p></blockquote><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 安装依赖</span></span>
<span class="line"><span style="color:#A6ACCD;">yum </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">y install zlib ruby rubygems</span></span>
<span class="line"><span style="color:#A6ACCD;">gem install redis</span></span></code></pre></div><p>然后通过命令来管理集群：</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 进入redis的src目录</span></span>
<span class="line"><span style="color:#A6ACCD;">cd </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">tmp</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">-</span><span style="color:#F78C6C;">6.2.4</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">src</span></span>
<span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 创建集群</span></span>
<span class="line"><span style="color:#89DDFF;">./</span><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">trib</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">rb create </span><span style="color:#89DDFF;">--</span><span style="color:#A6ACCD;">replicas </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">192.168.150.101</span><span style="color:#A6ACCD;">:</span><span style="color:#F78C6C;">7001</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">192.168.150.101</span><span style="color:#A6ACCD;">:</span><span style="color:#F78C6C;">7002</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">192.168.150.101</span><span style="color:#A6ACCD;">:</span><span style="color:#F78C6C;">7003</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">192.168.150.101</span><span style="color:#A6ACCD;">:</span><span style="color:#F78C6C;">8001</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">192.168.150.101</span><span style="color:#A6ACCD;">:</span><span style="color:#F78C6C;">8002</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">192.168.150.101</span><span style="color:#A6ACCD;">:</span><span style="color:#F78C6C;">8003</span></span></code></pre></div><blockquote><p>2）Redis5.0以后：我们使用的是Redis6.2.4版本，集群管理以及集成到了redis-cli中，格式如下：</p></blockquote><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#FFCB6B;">redis-cli</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">--cluster</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">--cluster-replicas</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">192.168</span><span style="color:#C3E88D;">.22.145:7001</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">192.168</span><span style="color:#C3E88D;">.22.145:7002</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">192.168</span><span style="color:#C3E88D;">.22.145:7003</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">192.168</span><span style="color:#C3E88D;">.22.145:8001</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">192.168</span><span style="color:#C3E88D;">.22.145:8002</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">192.168</span><span style="color:#C3E88D;">.22.145:8003</span></span></code></pre></div><ul><li><code>redis-cli --cluster</code>或者<code>./redis-trib.rb</code>：代表集群操作命令</li><li><code>create</code>：代表是创建集群</li><li><code>--replicas 1</code>或者<code>--cluster-replicas 1</code> ：指定集群中每个master的副本个数为1，此时<code>节点总数 ÷ (replicas + 1)</code> 得到的就是master的数量。因此节点列表中的前n个就是master，其它节点都是slave节点，随机分配到不同master</li></ul><p>运行后输入yes，则集群开始创建：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209171204906.png" alt="image-20220917120436756" style="zoom:80%;"><h3 id="查看集群状态" tabindex="-1">查看集群状态 <a class="header-anchor" href="#查看集群状态" aria-label="Permalink to &quot;查看集群状态&quot;">​</a></h3><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#FFCB6B;">redis-cli</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-p</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7001</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">cluster</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">nodes</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209171205770.png" alt="image-20220917120545589" style="zoom:80%;"><h3 id="测试集群" tabindex="-1">测试集群 <a class="header-anchor" href="#测试集群" aria-label="Permalink to &quot;测试集群&quot;">​</a></h3><p>尝试连接7001节点，存储一个数据：</p><p>集群操作时，需要给<code>redis-cli</code>加上<code>-c</code>参数才可以：</p><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;"># 连接</span></span>
<span class="line"><span style="color:#FFCB6B;">redis-cli</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-c</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-p</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7001</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 存储数据</span></span>
<span class="line"><span style="color:#82AAFF;">set</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">num</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">123</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 读取数据</span></span>
<span class="line"><span style="color:#FFCB6B;">get</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">num</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 再次存储</span></span>
<span class="line"><span style="color:#82AAFF;">set</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">a</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041414141.png" alt="image-20220504141453038" style="zoom:80%;"><blockquote><p>在redis-cli每次录入、查询键值，redis都会计算出该key应该送往的插槽，如果不是该客户端对应服务器的插槽，redis会报错，并告知应前往的redis实例地址和端口。redis-cli客户端提供了 –c 参数实现自动重定向</p></blockquote><h2 id="散列插槽" tabindex="-1">散列插槽 <a class="header-anchor" href="#散列插槽" aria-label="Permalink to &quot;散列插槽&quot;">​</a></h2><blockquote><p>Redis会把每一个master节点映射到0~16383共16384个插槽（hash slot）上，查看集群信息时就能看到：</p></blockquote><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">cli </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p </span><span style="color:#F78C6C;">7001</span><span style="color:#A6ACCD;"> cluster nodes</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041418044.png" alt="image-20220504141851954" style="zoom:67%;"><p>数据key不是与节点绑定，而是与插槽绑定。redis会根据key的有效部分计算插槽值，分两种情况：</p><blockquote><ul><li>key中包含&quot;{}&quot;，且“{}”中至少包含1个字符，“{}”中的部分是有效部分</li><li>key中不包含“{}”，整个key都是有效部分</li></ul></blockquote><blockquote><p>例如：key是num，那么就根据num计算，如果是{itcast}num，则根据itcast计算。计算方式是利用CRC16算法得到一个hash值，然后对16384取余，得到的结果就是slot值。</p></blockquote><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">cli </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">c </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p </span><span style="color:#F78C6C;">7001</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041419935.png" alt="image-20220504141925861" style="zoom:80%;"><p>Redis如何判断某个key应该在哪个实例？</p><blockquote><ul><li>将16384个插槽分配到不同的实例</li><li><strong>根据key的有效部分计算哈希值，对16384取余</strong></li><li><strong>余数作为插槽，寻找插槽所在实例即可</strong></li></ul></blockquote><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">cli </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">c </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p </span><span style="color:#F78C6C;">7001</span></span>
<span class="line"><span style="color:#A6ACCD;">set a </span><span style="color:#F78C6C;">101</span></span>
<span class="line"><span style="color:#A6ACCD;">set b </span><span style="color:#F78C6C;">102</span></span>
<span class="line"><span style="color:#A6ACCD;">set c </span><span style="color:#F78C6C;">103</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041434868.png" alt="image-20220504143433750" style="zoom:80%;"><blockquote><p>如何将同一类数据固定的保存在同一个Redis实例？这一类数据使用相同的有效部分，例如key都以{typeId}为前缀(这样这些数据就会存在一个redis机器中了)，不在一个slot下的键值，是不能使用mget,mset等多键操作。</p></blockquote><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">set </span><span style="color:#89DDFF;">{</span><span style="color:#A6ACCD;">a</span><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;">num1 </span><span style="color:#F78C6C;">111</span></span>
<span class="line"><span style="color:#A6ACCD;">set </span><span style="color:#89DDFF;">{</span><span style="color:#A6ACCD;">a</span><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;">qum1 </span><span style="color:#F78C6C;">113</span></span></code></pre></div><blockquote><p>可以通过{}来定义组的概念，从而使key中{}内相同内容的键值对放到一个slot中去</p></blockquote><div class="language-assembly"><button title="Copy Code" class="copy"></button><span class="lang">assembly</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">mset k1{c1} v1 k2{c1} v2</span></span>
<span class="line"><span style="color:#A6ACCD;">mget k1{c1} k2{c1}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209171211147.png" alt="image-20220917121118995" style="zoom:80%;"><h2 id="集群伸缩" tabindex="-1">集群伸缩 <a class="header-anchor" href="#集群伸缩" aria-label="Permalink to &quot;集群伸缩&quot;">​</a></h2><blockquote><p>redis-cli --cluster提供了很多操作集群的命令，可以通过下面方式查看：</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041420336.png" alt="image-20220504142021243" style="zoom:80%;"><blockquote><p>比如，添加节点的命令：</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041420338.png" alt="image-20220504142039268" style="zoom:80%;"><h3 id="新增节点" tabindex="-1">新增节点 <a class="header-anchor" href="#新增节点" aria-label="Permalink to &quot;新增节点&quot;">​</a></h3><blockquote><p>主要问题：插槽分配问题</p></blockquote><p>向集群中添加一个新的master节点，并向其中存储 num = 10</p><blockquote><ul><li>启动一个新的redis实例，端口为7004</li><li>添加7004到之前的集群，并作为一个master节点</li><li>给7004节点分配插槽，使得num这个key可以存储到7004实例</li></ul></blockquote><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 仿照上面进行新增</span></span>
<span class="line"><span style="color:#A6ACCD;">cd </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">tmp</span></span>
<span class="line"><span style="color:#A6ACCD;">mkdir </span><span style="color:#F78C6C;">7004</span></span>
<span class="line"><span style="color:#A6ACCD;">echo </span><span style="color:#F78C6C;">7004</span><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">|</span><span style="color:#A6ACCD;"> xargs </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">t </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">n </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;"> cp redis</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">conf</span></span>
<span class="line"><span style="color:#A6ACCD;">printf </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">%s\n</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7004</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">|</span><span style="color:#A6ACCD;"> xargs </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">I</span><span style="color:#89DDFF;">{}</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">t sed </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">i </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">s/6379/{}/g</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{}/</span><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">conf</span></span>
<span class="line"><span style="color:#A6ACCD;">printf </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">%s\n</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7004</span><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">|</span><span style="color:#A6ACCD;"> xargs </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">I</span><span style="color:#89DDFF;">{}</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">t redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">server </span><span style="color:#89DDFF;">{}/</span><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">conf</span></span>
<span class="line"><span style="color:#A6ACCD;">ps </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">ef </span><span style="color:#89DDFF;">|</span><span style="color:#A6ACCD;"> grep redis</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041446488.png" alt="image-20220504144600383" style="zoom:80%;"><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7004</span><span style="color:#A6ACCD;">是新增节点，</span><span style="color:#F78C6C;">7001</span><span style="color:#A6ACCD;">是随便在集群中存在的一个节点</span></span>
<span class="line"><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">cli </span><span style="color:#89DDFF;">--</span><span style="color:#A6ACCD;">cluster add</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">node </span><span style="color:#F78C6C;">192.168.22.145</span><span style="color:#A6ACCD;">:</span><span style="color:#F78C6C;">7004</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">192.168.22.145</span><span style="color:#A6ACCD;">:</span><span style="color:#F78C6C;">7001</span></span></code></pre></div><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">cli </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p </span><span style="color:#F78C6C;">7001</span><span style="color:#A6ACCD;"> cluster nodes</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041447722.png" alt="image-20220504144721566" style="zoom:80%;"><p>以上可以发现7004没有插槽</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 查看num所在插槽</span></span>
<span class="line"><span style="color:#A6ACCD;">get num</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041448590.png" alt="image-20220504144832494" style="zoom:80%;"><p>进行重新分片：从7001里拿取分片</p><p>我们可以将0~3000的插槽从7001转移到7004，命令格式如下：</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">cli </span><span style="color:#89DDFF;">--</span><span style="color:#A6ACCD;">cluster reshard </span><span style="color:#F78C6C;">192.168.22.145</span><span style="color:#A6ACCD;">:</span><span style="color:#F78C6C;">7001</span></span></code></pre></div><p>得到下面的反馈</p><p>询问要移动多少个插槽，我们计划是3000个：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041502999.png" alt="image-20210725161540841" style="zoom:67%;"><p>新的问题来了：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041502000.png" alt="image-20210725161637152" style="zoom:67%;"><p>那个node来接收这些插槽？？</p><p>显然是7004，那么7004节点的id是多少呢？上面给的显示7004ID</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041502008.png" alt="image-20210725161731738" style="zoom:67%;"><p>复制这个id，然后拷贝到刚才的控制台后：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041502009.png" alt="image-20210725161817642" style="zoom:67%;"><p>这里询问，你的插槽是从哪里移动过来的？</p><ul><li>all：代表全部，也就是三个节点各转移一部分</li><li>具体的id：目标节点的id</li><li>done：没有了</li></ul><p>这里我们要从7001获取，因此填写7001的id：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041502492.png" alt="image-20210725162030478" style="zoom:67%;"><p>填完后，点击done，这样插槽转移就准备好了：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041502508.png" alt="image-20210725162101228" style="zoom:67%;"><p>确认要转移吗？输入yes：</p><p>然后，通过命令查看结果：</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 可以发现</span><span style="color:#F78C6C;">0</span><span style="color:#89DDFF;">-</span><span style="color:#F78C6C;">2999</span><span style="color:#A6ACCD;">被分到</span><span style="color:#F78C6C;">7004</span></span>
<span class="line"><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">cli </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p </span><span style="color:#F78C6C;">7001</span><span style="color:#A6ACCD;"> cluster nodes</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041453129.png" alt="image-20220504145334966" style="zoom:80%;"><p>目的达成</p><h3 id="删除节点" tabindex="-1">删除节点 <a class="header-anchor" href="#删除节点" aria-label="Permalink to &quot;删除节点&quot;">​</a></h3><p>删除集群中的一个节点</p><p>需求：删除7004这个实例</p><p>首先将7004插槽还给7001(任何节点都行)</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">cli </span><span style="color:#89DDFF;">--</span><span style="color:#A6ACCD;">cluster reshard </span><span style="color:#F78C6C;">192.168.22.145</span><span style="color:#A6ACCD;">:</span><span style="color:#F78C6C;">7004</span></span></code></pre></div><blockquote><p>3000表示7004的插槽数量，7001ID表示7001接收插槽，</p></blockquote><p>依次输入3000、7001ID、7004ID、done、yes，即可完成分配</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">cli </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p </span><span style="color:#F78C6C;">7001</span><span style="color:#A6ACCD;"> cluster nodes</span></span></code></pre></div><p>可以看到7004没插槽了</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">cli </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p </span><span style="color:#F78C6C;">7001</span><span style="color:#A6ACCD;"> cluster nodes</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041512033.png" alt="image-20220504151235853" style="zoom:80%;"><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 删除</span><span style="color:#F78C6C;">7004</span><span style="color:#A6ACCD;">节点，最后一个是</span><span style="color:#F78C6C;">7004</span><span style="color:#A6ACCD;">的ID</span></span>
<span class="line"><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">cli </span><span style="color:#89DDFF;">--</span><span style="color:#A6ACCD;">cluster  del</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">node </span><span style="color:#F78C6C;">192.168.22.145</span><span style="color:#A6ACCD;">:</span><span style="color:#F78C6C;">7004</span><span style="color:#A6ACCD;"> f0141dd210196a82a7e8d38203f589286214436c</span></span></code></pre></div><p>再次查看7004删除完成</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">cli </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p </span><span style="color:#F78C6C;">7001</span><span style="color:#A6ACCD;"> cluster nodes</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041514457.png" alt="image-20220504151426289" style="zoom:80%;"><h2 id="故障转移" tabindex="-1">故障转移 <a class="header-anchor" href="#故障转移" aria-label="Permalink to &quot;故障转移&quot;">​</a></h2><blockquote><p>如果主节点下线？从节点能否自动升为主节点？注意：<strong>15</strong>秒超时，主节点恢复后，主从关系会如何？<strong>主节点回来变成从机</strong>，如果所有某一段插槽的主从节点都宕掉，redis服务是否还能继续?</p></blockquote><blockquote><p>如果某一段插槽的主从都挂掉，而cluster-require-full-coverage 为yes ，那么 ，整个集群都挂掉</p><p>如果某一段插槽的主从都挂掉，而cluster-require-full-coverage 为no ，那么，该插槽数据全都不能使用，也无法存储。</p></blockquote><p><strong>当集群中有一个master宕机会发生什么呢？</strong></p><blockquote><p>1.首先是该实例与其它实例失去连接</p><p>2.然后是疑似宕机</p></blockquote><h3 id="自动故障转移" tabindex="-1">自动故障转移 <a class="header-anchor" href="#自动故障转移" aria-label="Permalink to &quot;自动故障转移&quot;">​</a></h3><p>当集群中有一个master宕机会发生什么呢？</p><h4 id="监控集群状态" tabindex="-1">监控集群状态 <a class="header-anchor" href="#监控集群状态" aria-label="Permalink to &quot;监控集群状态&quot;">​</a></h4><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 利用watch监控集群状态</span></span>
<span class="line"><span style="color:#A6ACCD;">watch redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">cli </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p </span><span style="color:#F78C6C;">7001</span><span style="color:#A6ACCD;"> cluster nodes</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209171221257.png" alt="image-20220917122135069" style="zoom:80%;"><h4 id="手动宕机7002" tabindex="-1">手动宕机7002 <a class="header-anchor" href="#手动宕机7002" aria-label="Permalink to &quot;手动宕机7002&quot;">​</a></h4><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;"># 直接停止一个redis实例，例如7002：</span></span>
<span class="line"><span style="color:#FFCB6B;">redis-cli</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-p</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">7002</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">shutdown</span></span></code></pre></div><p>1）首先是该实例与其它实例失去连接</p><p>2）然后是疑似宕机：</p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041515122.png" alt="image-20210725162319490"></p><p>3）最后是确定下线，自动提升一个slave为新的master：</p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041515129.png" alt="image-20210725162408979"></p><p>4）当7002再次启动，就会变为一个slave节点了：</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">server </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">tmp</span><span style="color:#89DDFF;">/</span><span style="color:#F78C6C;">7002</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">conf</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209171226449.png" alt="image-20220917122620283" style="zoom:80%;"><h3 id="手动故障转移-抢走主节点" tabindex="-1">手动故障转移(抢走主节点) <a class="header-anchor" href="#手动故障转移-抢走主节点" aria-label="Permalink to &quot;手动故障转移(抢走主节点)&quot;">​</a></h3><blockquote><p>利用cluster failover命令可以手动让集群中的某个master宕机，切换到执行cluster failover命令的这个slave节点，实现无感知的数据迁移。其流程如下：</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041515134.png" alt="image-20210725162441407" style="zoom:67%;"><p>这种failover命令可以指定三种模式：</p><ul><li>缺省：默认的流程，如图1~6歩</li><li>force：省略了对offset的一致性校验</li><li>takeover：直接执行第5歩，忽略数据一致性、忽略master状态和其它master的意见</li></ul><p><strong>案例需求</strong>：在7002这个slave节点执行手动故障转移，重新夺回master地位</p><blockquote><p>1）利用redis-cli连接7002这个节点</p><p>2）执行cluster failover命令</p></blockquote><p>如图：</p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041515135.png" alt="image-20210727160037766"></p><p>效果：</p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205041515146.png" alt="image-20210727161152065"></p><h1 id="多级缓存" tabindex="-1">多级缓存 <a class="header-anchor" href="#多级缓存" aria-label="Permalink to &quot;多级缓存&quot;">​</a></h1><blockquote><p>多级缓存的实现离不开Nginx编程，而Nginx编程又离不开OpenResty。</p><p>项目地址：<a href="https://gitee.com/sure-s-renshuo/item-service" target="_blank" rel="noreferrer">https://gitee.com/sure-s-renshuo/item-service</a></p></blockquote><h2 id="多级缓存架构⭐" tabindex="-1">多级缓存架构⭐ <a class="header-anchor" href="#多级缓存架构⭐" aria-label="Permalink to &quot;多级缓存架构⭐&quot;">​</a></h2><blockquote><p>多级缓存就是充分利用请求处理的每个环节，分别添加缓存，减轻Tomcat压力，提升服务性能</p></blockquote><h3 id="完整架构" tabindex="-1">完整架构 <a class="header-anchor" href="#完整架构" aria-label="Permalink to &quot;完整架构&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202306131011290.png" alt="image-20230613101147101" style="zoom:80%;"><h3 id="查询数据流程" tabindex="-1">查询数据流程 <a class="header-anchor" href="#查询数据流程" aria-label="Permalink to &quot;查询数据流程&quot;">​</a></h3><blockquote><ul><li>浏览器访问静态资源时，优先读取浏览器本地缓存</li><li>访问非静态资源（ajax查询数据）时，访问服务端</li><li>请求到达Nginx后，优先读取Nginx本地缓存</li><li>如果Nginx本地缓存未命中，则去直接查询Redis（不经过Tomcat）</li><li>如果Redis查询未命中，则查询Tomcat</li><li>请求进入Tomcat后，优先查询JVM进程缓存</li><li>如果JVM进程缓存未命中，则查询数据库</li></ul></blockquote><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20210821075558137.png" alt="image-20210821075558137"></p><h3 id="nginx集群" tabindex="-1">Nginx集群 <a class="header-anchor" href="#nginx集群" aria-label="Permalink to &quot;Nginx集群&quot;">​</a></h3><blockquote><p>在多级缓存架构中，Nginx内部需要编写本地缓存查询、Redis查询、Tomcat查询的业务逻辑，因此这样的nginx服务不再是一个<strong>反向代理服务器</strong>，而是一个编写<strong>业务的Web服务器了</strong>。因此这样的业务Nginx服务也需要搭建集群来提高并发，再有专门的nginx服务来做反向代理，如图：</p></blockquote><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20210821080511581.png" alt="image-20210821080511581"></p><h3 id="tomcat集群" tabindex="-1">Tomcat集群 <a class="header-anchor" href="#tomcat集群" aria-label="Permalink to &quot;Tomcat集群&quot;">​</a></h3><p>另外，我们的Tomcat服务将来也会部署为集群模式：</p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20210821080954947.png" alt="image-20210821080954947"></p><p>可见，多级缓存的关键有两个</p><blockquote><ul><li><p>一个是在nginx中编写业务，实现nginx本地缓存、Redis、Tomcat的查询</p></li><li><p>另一个就是在Tomcat中实现JVM进程缓存</p></li></ul></blockquote><h2 id="项目搭建" tabindex="-1">项目搭建 <a class="header-anchor" href="#项目搭建" aria-label="Permalink to &quot;项目搭建&quot;">​</a></h2><h3 id="数据库表" tabindex="-1">数据库表 <a class="header-anchor" href="#数据库表" aria-label="Permalink to &quot;数据库表&quot;">​</a></h3><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">drop</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">table</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">exists</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">tb_item</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">table</span><span style="color:#A6ACCD;"> `</span><span style="color:#82AAFF;">tb_item</span><span style="color:#A6ACCD;">`  (</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">id</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">bigint</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">20</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">not null</span><span style="color:#A6ACCD;"> auto_increment comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">商品id</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">title</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">varchar</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">264</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">not null</span><span style="color:#A6ACCD;"> comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">商品标题</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">name</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">varchar</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">128</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">not null</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">default</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;&#39;</span><span style="color:#A6ACCD;"> comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">商品名称</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">price</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">bigint</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">20</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">not null</span><span style="color:#A6ACCD;"> comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">价格（分）</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">image</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">varchar</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">200</span><span style="color:#A6ACCD;">) </span><span style="color:#C792EA;">default</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;"> comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">商品图片</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">category</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">varchar</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">200</span><span style="color:#A6ACCD;">) </span><span style="color:#C792EA;">default</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;"> comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">类目名称</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">brand</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">varchar</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">100</span><span style="color:#A6ACCD;">) </span><span style="color:#C792EA;">default</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;"> comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">品牌名称</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">spec</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">varchar</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">200</span><span style="color:#A6ACCD;">) </span><span style="color:#C792EA;">default</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;"> comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">规格</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">status</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">default</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;"> comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">商品状态 1-正常，2-下架，3-删除</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">create_time</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">datetime</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">default</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;"> comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">创建时间</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">update_time</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">datetime</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">default</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;"> comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">更新时间</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#C792EA;">primary key</span><span style="color:#A6ACCD;"> (</span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">id</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">using</span><span style="color:#A6ACCD;"> btree,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">status</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">status</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">using</span><span style="color:#A6ACCD;"> btree,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">updated</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">update_time</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">using</span><span style="color:#A6ACCD;"> btree</span></span>
<span class="line"><span style="color:#A6ACCD;">) engine </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> innodb auto_increment </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">  comment </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">商品表</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">drop</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">table</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">exists</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">tb_item_stock</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">table</span><span style="color:#A6ACCD;"> `</span><span style="color:#82AAFF;">tb_item_stock</span><span style="color:#A6ACCD;">`  (</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">item_id</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">bigint</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">20</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">not null</span><span style="color:#A6ACCD;"> comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">商品id，关联tb_item表</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">stock</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">10</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">not null</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">default</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">9999</span><span style="color:#A6ACCD;"> comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">商品库存</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">sold</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">10</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">not null</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">default</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#A6ACCD;"> comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">商品销量</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#C792EA;">primary key</span><span style="color:#A6ACCD;"> (</span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">item_id</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">using</span><span style="color:#A6ACCD;"> btree</span></span>
<span class="line"><span style="color:#A6ACCD;">) engine </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> innodb </span><span style="color:#F78C6C;">character</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">set</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> utf8mb4;</span></span></code></pre></div><h3 id="pom-xml" tabindex="-1">pom.xml <a class="header-anchor" href="#pom-xml" aria-label="Permalink to &quot;pom.xml&quot;">​</a></h3><div class="language-xml"><button title="Copy Code" class="copy"></button><span class="lang">xml</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependencies</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">org.springframework.boot</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">spring-boot-starter-web</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">mysql</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">mysql-connector-java</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#676E95;font-style:italic;">&lt;!--mybatis--&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">com.baomidou</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">mybatis-plus-boot-starter</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">version</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">3.4.2</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">version</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">org.projectlombok</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">lombok</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">com.github.ben-manes.caffeine</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">caffeine</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">org.springframework.boot</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">spring-boot-starter-test</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependencies</span><span style="color:#89DDFF;">&gt;</span></span></code></pre></div><div class="language-yml"><button title="Copy Code" class="copy"></button><span class="lang">yml</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F07178;">server</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F07178;">port</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">8081</span></span>
<span class="line"><span style="color:#F07178;">spring</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F07178;">application</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F07178;">name</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">itemservice</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F07178;">datasource</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F07178;">url</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">jdbc:mysql://127.0.0.1:3306/xue?useSSL=false</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F07178;">username</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">root</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F07178;">password</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">123456</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F07178;">driver-class-name</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">com.mysql.cj.jdbc.Driver</span></span>
<span class="line"><span style="color:#F07178;">mybatis-plus</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F07178;">type-aliases-package</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">com.heima.item.pojo</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F07178;">configuration</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F07178;">map-underscore-to-camel-case</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#FF9CAC;">true</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F07178;">global-config</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F07178;">db-config</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">      </span><span style="color:#F07178;">update-strategy</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">not_null</span></span>
<span class="line"><span style="color:#A6ACCD;">      </span><span style="color:#F07178;">id-type</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">auto</span></span>
<span class="line"><span style="color:#F07178;">logging</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F07178;">level</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F07178;">com.heima</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">debug</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F07178;">pattern</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F07178;">dateformat</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">HH:mm:ss:SSS</span></span></code></pre></div><h3 id="entity" tabindex="-1">entity <a class="header-anchor" href="#entity" aria-label="Permalink to &quot;entity&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Data</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">TableName</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">tb_item</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">Item</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">TableId</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">type</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> IdType</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">AUTO</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> id</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//商品id</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> name</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//商品名称</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> title</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//商品标题</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> price</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//价格（分）</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> image</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//商品图片</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> category</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//分类名称</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> brand</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//品牌名称</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> spec</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//规格</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Integer</span><span style="color:#A6ACCD;"> status</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//商品状态 1-正常，2-下架</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Date</span><span style="color:#A6ACCD;"> createTime</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//创建时间</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Date</span><span style="color:#A6ACCD;"> updateTime</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//更新时间</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">TableField</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">exist</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">false)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Integer</span><span style="color:#A6ACCD;"> stock</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">TableField</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">exist</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">false)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Integer</span><span style="color:#A6ACCD;"> sold</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Data</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">TableName</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">tb_item_stock</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">ItemStock</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">TableId</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">type</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> IdType</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">INPUT</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">value</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">item_id</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> id</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;">//商品id</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Integer</span><span style="color:#A6ACCD;"> stock</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;">//商品库存</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Integer</span><span style="color:#A6ACCD;"> sold</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;">//商品销量</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Data</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">NoArgsConstructor</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">AllArgsConstructor</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">PageDTO</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> total</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">List</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Item</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> list</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="mapper" tabindex="-1">Mapper <a class="header-anchor" href="#mapper" aria-label="Permalink to &quot;Mapper&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">interface</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">ItemMapper</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">extends</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">BaseMapper</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Item</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">interface</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">ItemStockMapper</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">extends</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">BaseMapper</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">ItemStock</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="service" tabindex="-1">Service <a class="header-anchor" href="#service" aria-label="Permalink to &quot;Service&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">interface</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">IItemService</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">extends</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">IService</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Item</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">saveItem</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">Item</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">item</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">interface</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">IItemStockService</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">extends</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">IService</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">ItemStock</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Service</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">ItemService</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">extends</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">ServiceImpl</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">ItemMapper</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Item</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">implements</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">IItemService</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Autowired</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">IItemStockService</span><span style="color:#A6ACCD;"> stockService</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Override</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Transactional</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">saveItem</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">Item</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">item</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 新增商品</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#82AAFF;">save</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">item</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 新增库存</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">ItemStock</span><span style="color:#A6ACCD;"> stock </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">ItemStock</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">        stock</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setId</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">item</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getId</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#A6ACCD;">        stock</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setStock</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">item</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getStock</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#A6ACCD;">        stockService</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">save</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">stock</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Service</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">ItemStockService</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">extends</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">ServiceImpl</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">ItemStockMapper</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">ItemStock</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span></span>
<span class="line"><span style="color:#A6ACCD;">                              </span><span style="color:#C792EA;">implements</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">IItemStockService</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="controller" tabindex="-1">controller <a class="header-anchor" href="#controller" aria-label="Permalink to &quot;controller&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">RestController</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">RequestMapping</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">item</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">ItemController</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Autowired</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">IItemService</span><span style="color:#A6ACCD;"> itemService</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Autowired</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">IItemStockService</span><span style="color:#A6ACCD;"> stockService</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">GetMapping</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">list</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">PageDTO</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">queryItemPage</span><span style="color:#89DDFF;">(</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">RequestParam</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">value</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">page</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">defaultValue</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Integer</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">page</span><span style="color:#89DDFF;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">RequestParam</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">value</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">size</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">defaultValue</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">5</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Integer</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">size</span><span style="color:#89DDFF;">){</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 分页查询商品</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">Page</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Item</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> result </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> itemService</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">query</span><span style="color:#89DDFF;">()</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">ne</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">status</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">3</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">page</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Page</span><span style="color:#89DDFF;">&lt;&gt;(</span><span style="color:#A6ACCD;">page</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> size</span><span style="color:#89DDFF;">));</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 查询库存</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">List</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Item</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> list </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> result</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getRecords</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">stream</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">peek</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">item </span><span style="color:#C792EA;">-&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#C792EA;">ItemStock</span><span style="color:#A6ACCD;"> stock </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> stockService</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getById</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">item</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getId</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#A6ACCD;">            item</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setStock</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">stock</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getStock</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#A6ACCD;">            item</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setSold</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">stock</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getSold</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}).</span><span style="color:#82AAFF;">collect</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">Collectors</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">toList</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 封装返回</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">PageDTO</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">result</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getTotal</span><span style="color:#89DDFF;">(),</span><span style="color:#A6ACCD;"> list</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">PostMapping</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">saveItem</span><span style="color:#89DDFF;">(@</span><span style="color:#C792EA;">RequestBody</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Item</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">item</span><span style="color:#89DDFF;">){</span></span>
<span class="line"><span style="color:#A6ACCD;">        itemService</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">saveItem</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">item</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">PutMapping</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">updateItem</span><span style="color:#89DDFF;">(@</span><span style="color:#C792EA;">RequestBody</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Item</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">item</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        itemService</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">updateById</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">item</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">PutMapping</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">stock</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">updateStock</span><span style="color:#89DDFF;">(@</span><span style="color:#C792EA;">RequestBody</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">ItemStock</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">itemStock</span><span style="color:#89DDFF;">){</span></span>
<span class="line"><span style="color:#A6ACCD;">        stockService</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">updateById</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">itemStock</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">DeleteMapping</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">/{id}</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">deleteById</span><span style="color:#89DDFF;">(@</span><span style="color:#C792EA;">PathVariable</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">id</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">id</span><span style="color:#89DDFF;">){</span></span>
<span class="line"><span style="color:#A6ACCD;">        itemService</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">update</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">set</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">status</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">3</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">eq</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">id</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> id</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">update</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">GetMapping</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">/{id}</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Item</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">findById</span><span style="color:#89DDFF;">(@</span><span style="color:#C792EA;">PathVariable</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">id</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">id</span><span style="color:#89DDFF;">){</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> itemService</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">query</span><span style="color:#89DDFF;">()</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">ne</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">status</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">3</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">eq</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">id</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> id</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">one</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">GetMapping</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">/stock/{id}</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">ItemStock</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">findStockById</span><span style="color:#89DDFF;">(@</span><span style="color:#C792EA;">PathVariable</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">id</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">id</span><span style="color:#89DDFF;">){</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> stockService</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getById</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">id</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="访问测试" tabindex="-1">访问测试 <a class="header-anchor" href="#访问测试" aria-label="Permalink to &quot;访问测试&quot;">​</a></h3><p>:8081/item/list</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202306121645551.png" alt="image-20230612164525409" style="zoom:80%;"><h2 id="jvm进程缓存" tabindex="-1">JVM进程缓存 <a class="header-anchor" href="#jvm进程缓存" aria-label="Permalink to &quot;JVM进程缓存&quot;">​</a></h2><blockquote><p>缓存在日常开发中启动至关重要的作用，由于是存储在内存中，数据的读取速度是非常快的，能大量减少对数据库的访问，减少数据库的压力。我们把缓存分为两类：</p></blockquote><h3 id="本地进程缓存" tabindex="-1">本地进程缓存 <a class="header-anchor" href="#本地进程缓存" aria-label="Permalink to &quot;本地进程缓存&quot;">​</a></h3><p>分布式缓存，例如Redis：</p><blockquote><p>优点：存储容量更大、可靠性更好、可以在集群间共享</p><p>缺点：访问缓存有网络开销</p><p>场景：缓存数据量较大、可靠性要求较高、需要在集群间共享</p></blockquote><p>进程本地缓存，例如HashMap、GuavaCache：</p><blockquote><p>优点：读取本地内存，没有网络开销，速度更快</p><p>缺点：存储容量有限、可靠性较低、无法共享</p><p>场景：性能要求较高，缓存数据量较小</p></blockquote><blockquote><p>Caffeine是一个基于Java8开发的，提供了近乎最佳命中率的高性能的本地缓存库。目前Spring内部的缓存使用的就是Caffeine。GitHub地址：<a href="https://github.com/ben-manes/caffeine" target="_blank" rel="noreferrer">https://github.com/ben-manes/caffeine</a></p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202306121650118.png" alt="image-20230612165023002" style="zoom:80%;"><h3 id="基础语法" tabindex="-1">基础语法 <a class="header-anchor" href="#基础语法" aria-label="Permalink to &quot;基础语法&quot;">​</a></h3><div class="language-xml"><button title="Copy Code" class="copy"></button><span class="lang">xml</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">com.github.ben-manes.caffeine</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">caffeine</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span></code></pre></div><h4 id="基本用法" tabindex="-1">基本用法 <a class="header-anchor" href="#基本用法" aria-label="Permalink to &quot;基本用法&quot;">​</a></h4><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testBasicOps</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 创建缓存对象</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Cache</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> cache </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> Caffeine</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">newBuilder</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">build</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 存数据</span></span>
<span class="line"><span style="color:#A6ACCD;">    cache</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">put</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">gf</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">迪丽热巴</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 取数据，不存在则返回null</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> gf </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> cache</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getIfPresent</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">gf</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">gf = </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;"> gf</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 取数据，不存在则去数据库查询</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> defaultGF </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> cache</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">get</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">defaultGF</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> key </span><span style="color:#C792EA;">-&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 这里可以去数据库根据 key查询value</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">柳岩</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">});</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">defaultGF = </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;"> defaultGF</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h4 id="缓存驱逐策略" tabindex="-1">缓存驱逐策略 <a class="header-anchor" href="#缓存驱逐策略" aria-label="Permalink to &quot;缓存驱逐策略&quot;">​</a></h4><blockquote><p>在默认情况下，当一个缓存元素过期的时候，Caffeine不会自动立即将其清理和驱逐。而是在一次读或写操作后，或者在空闲时间完成对失效数据的驱逐。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202306121656935.png" alt="image-20230612165649799" style="zoom:80%;"><h4 id="基于大小设置驱逐策略" tabindex="-1">基于大小设置驱逐策略 <a class="header-anchor" href="#基于大小设置驱逐策略" aria-label="Permalink to &quot;基于大小设置驱逐策略&quot;">​</a></h4><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testEvictByNum</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> throws InterruptedException </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 创建缓存对象</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Cache</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> cache </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> Caffeine</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">newBuilder</span><span style="color:#89DDFF;">()</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">// 设置缓存大小上限为 1</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">maximumSize</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">build</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 存数据</span></span>
<span class="line"><span style="color:#A6ACCD;">    cache</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">put</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">gf1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">柳岩</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    cache</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">put</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">gf2</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">范冰冰</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    cache</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">put</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">gf3</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">迪丽热巴</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 延迟10ms，给清理线程一点时间</span></span>
<span class="line"><span style="color:#A6ACCD;">    Thread</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">sleep</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">10L</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 获取数据</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">gf1: </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;"> cache</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getIfPresent</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">gf1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">));</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">gf2: </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;"> cache</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getIfPresent</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">gf2</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">));</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">gf3: </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;"> cache</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getIfPresent</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">gf3</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">));</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h4 id="基于时间设置驱逐策略" tabindex="-1">基于时间设置驱逐策略 <a class="header-anchor" href="#基于时间设置驱逐策略" aria-label="Permalink to &quot;基于时间设置驱逐策略&quot;">​</a></h4><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testEvictByTime</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> throws InterruptedException </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 创建缓存对象</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Cache</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> cache </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> Caffeine</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">newBuilder</span><span style="color:#89DDFF;">()</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">expireAfterWrite</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">Duration</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">ofSeconds</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">))</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;">// 设置缓存有效期为 10 秒</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">build</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 存数据</span></span>
<span class="line"><span style="color:#A6ACCD;">    cache</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">put</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">gf</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">柳岩</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 获取数据</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">gf: </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;"> cache</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getIfPresent</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">gf</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">));</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 休眠一会儿</span></span>
<span class="line"><span style="color:#A6ACCD;">    Thread</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">sleep</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">1200L</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">gf: </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;"> cache</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getIfPresent</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">gf</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">));</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="实现进程缓存" tabindex="-1">实现进程缓存 <a class="header-anchor" href="#实现进程缓存" aria-label="Permalink to &quot;实现进程缓存&quot;">​</a></h3><blockquote><ul><li>给根据id查询商品的业务添加缓存，缓存未命中时查询数据库</li><li>给根据id查询商品库存的业务添加缓存，缓存未命中时查询数据库</li><li>缓存初始大小为100，缓存上限为10000</li></ul></blockquote><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Configuration</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">CacheConfig</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Bean</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Cache</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Object</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">caffeineCache</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> Caffeine</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">newBuilder</span><span style="color:#89DDFF;">()</span></span>
<span class="line"><span style="color:#89DDFF;">                </span><span style="color:#676E95;font-style:italic;">// 设置最后一次写入或访问后经过固定时间过期</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">expireAfterWrite</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">60</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">SECONDS</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">                </span><span style="color:#676E95;font-style:italic;">// 初始的缓存空间大小</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">initialCapacity</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">100</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">                </span><span style="color:#676E95;font-style:italic;">// 缓存的最大条数</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">maximumSize</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">10_000</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">build</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Bean</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Cache</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Long</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Item</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">itemCache</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> Caffeine</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">newBuilder</span><span style="color:#89DDFF;">()</span></span>
<span class="line"><span style="color:#89DDFF;">                </span><span style="color:#676E95;font-style:italic;">// 设置最后一次写入或访问后经过固定时间过期</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">expireAfterWrite</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">60</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">SECONDS</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">                </span><span style="color:#676E95;font-style:italic;">// 初始的缓存空间大小</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">initialCapacity</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">100</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">                </span><span style="color:#676E95;font-style:italic;">// 缓存的最大条数</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">maximumSize</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">10_000</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">build</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Bean</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Cache</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Long</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">ItemStock</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">stockCache</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> Caffeine</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">newBuilder</span><span style="color:#89DDFF;">()</span></span>
<span class="line"><span style="color:#89DDFF;">                </span><span style="color:#676E95;font-style:italic;">// 设置最后一次写入或访问后经过固定时间过期</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">expireAfterWrite</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">60</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">SECONDS</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">                </span><span style="color:#676E95;font-style:italic;">// 初始的缓存空间大小</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">initialCapacity</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">100</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">                </span><span style="color:#676E95;font-style:italic;">// 缓存的最大条数</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">maximumSize</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">10_000</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">build</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><blockquote><p>修改ItemController</p></blockquote><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Resource</span></span>
<span class="line"><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Cache</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Long</span><span style="color:#89DDFF;">,</span><span style="color:#C792EA;">Item</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> itemCache</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Resource</span></span>
<span class="line"><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Cache</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Long</span><span style="color:#89DDFF;">,</span><span style="color:#C792EA;">ItemStock</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> stockCache</span><span style="color:#89DDFF;">;</span></span></code></pre></div><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">GetMapping</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">/{id}</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Item</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">findById</span><span style="color:#89DDFF;">(@</span><span style="color:#C792EA;">PathVariable</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">id</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> id</span><span style="color:#89DDFF;">){</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 根据id查询，查不到就去数据库查询</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> itemCache</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">get</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">id</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">key </span><span style="color:#C792EA;">-&gt;</span><span style="color:#A6ACCD;"> itemService</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">query</span><span style="color:#89DDFF;">()</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">ne</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">status</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">3</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">eq</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">id</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> id</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">one</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">GetMapping</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">/stock/{id}</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">ItemStock</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">findStockById</span><span style="color:#89DDFF;">(@</span><span style="color:#C792EA;">PathVariable</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">id</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> id</span><span style="color:#89DDFF;">){</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 根据id查询，查不到就去数据库查询</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> stockCache</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">get</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">id</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">key </span><span style="color:#C792EA;">-&gt;</span><span style="color:#A6ACCD;"> stockService</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getById</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">id</span><span style="color:#89DDFF;">));</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><blockquote><p>访问测试：:8081/item/10001，多次访问该路径，只进行了一次查询数据库</p><p>访问测试：:8081/item/stock/10001，多次访问该路径，只进行了一次查询数据库</p></blockquote><h2 id="nginx查询接口数据" tabindex="-1">Nginx查询接口数据 <a class="header-anchor" href="#nginx查询接口数据" aria-label="Permalink to &quot;Nginx查询接口数据&quot;">​</a></h2><h3 id="安装openresty" tabindex="-1">安装OpenResty <a class="header-anchor" href="#安装openresty" aria-label="Permalink to &quot;安装OpenResty&quot;">​</a></h3><blockquote><p>OpenResty® 是一个基于 Nginx的高性能 Web 平台，用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。具备下列特点：官方网站： <a href="https://openresty.org/cn/" target="_blank" rel="noreferrer">https://openresty.org/cn/</a></p></blockquote><blockquote><ul><li>具备Nginx的完整功能</li><li>基于Lua语言进行扩展，集成了大量精良的 Lua 库、第三方模块</li><li>允许使用Lua<strong>自定义业务逻辑</strong>、<strong>自定义库</strong></li></ul></blockquote><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20210821092902946.png" alt="image-20210821092902946"></p><p>首先你的Linux虚拟机必须联网</p><h4 id="_1-安装开发库" tabindex="-1">1）安装开发库 <a class="header-anchor" href="#_1-安装开发库" aria-label="Permalink to &quot;1）安装开发库&quot;">​</a></h4><p>首先要安装OpenResty的依赖开发库，执行命令：</p><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#FFCB6B;">yum</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">install</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-y</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">pcre-devel</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">openssl-devel</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">gcc</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">--skip-broken</span></span></code></pre></div><h4 id="_2-安装openresty仓库" tabindex="-1">2）安装OpenResty仓库 <a class="header-anchor" href="#_2-安装openresty仓库" aria-label="Permalink to &quot;2）安装OpenResty仓库&quot;">​</a></h4><blockquote><p>你可以在你的 CentOS 系统中添加 <code>openresty</code> 仓库，这样就可以便于未来安装或更新我们的软件包（通过 <code>yum check-update</code> 命令）。运行下面的命令就可以添加我们的仓库：</p></blockquote><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">yum</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">config</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">manager </span><span style="color:#89DDFF;">--</span><span style="color:#A6ACCD;">add</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">repo https:</span><span style="color:#89DDFF;">//</span><span style="color:#A6ACCD;">openresty</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">org</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">package</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">centos</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">openresty</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">repo</span></span></code></pre></div><p>如果提示说命令不存在，则运行：然后再重复上面的命令</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">yum install </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">y yum</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">utils</span></span></code></pre></div><h4 id="_3-安装openresty" tabindex="-1">3）安装OpenResty <a class="header-anchor" href="#_3-安装openresty" aria-label="Permalink to &quot;3）安装OpenResty&quot;">​</a></h4><p>然后就可以像下面这样安装软件包，比如 <code>openresty</code>：</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">yum install </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">y openresty</span></span></code></pre></div><h4 id="_4-安装opm工具" tabindex="-1">4）安装opm工具 <a class="header-anchor" href="#_4-安装opm工具" aria-label="Permalink to &quot;4）安装opm工具&quot;">​</a></h4><p>opm是OpenResty的一个管理工具，可以帮助我们安装一个第三方的Lua模块。</p><p>如果你想安装命令行工具 <code>opm</code>，那么可以像下面这样安装 <code>openresty-opm</code> 包：</p><div class="language-bash"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#FFCB6B;">yum</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">install</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-y</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">openresty-opm</span></span></code></pre></div><h4 id="_5-目录结构" tabindex="-1">5）目录结构 <a class="header-anchor" href="#_5-目录结构" aria-label="Permalink to &quot;5）目录结构&quot;">​</a></h4><p>默认情况下，OpenResty安装的目录是：/usr/local/openresty</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">cd </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">usr</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">local</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">openresty</span></span></code></pre></div><p>看到里面的nginx目录了吗，OpenResty就是在Nginx基础上集成了一些Lua模块。</p><h4 id="_6-配置nginx的环境变量" tabindex="-1">6）配置nginx的环境变量 <a class="header-anchor" href="#_6-配置nginx的环境变量" aria-label="Permalink to &quot;6）配置nginx的环境变量&quot;">​</a></h4><blockquote><p>打开配置文件，在最下面加入两行：</p></blockquote><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">vi </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">etc</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">profile</span></span></code></pre></div><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">export</span><span style="color:#A6ACCD;"> NGINX_HOME</span><span style="color:#89DDFF;">=</span><span style="color:#C3E88D;">/usr/local/openresty/nginx</span></span>
<span class="line"><span style="color:#C792EA;">export</span><span style="color:#A6ACCD;"> PATH</span><span style="color:#89DDFF;">=${</span><span style="color:#A6ACCD;">NGINX_HOME</span><span style="color:#89DDFF;">}</span><span style="color:#C3E88D;">/sbin:</span><span style="color:#A6ACCD;">$PATH</span></span></code></pre></div><blockquote><p>NGINX_HOME：后面是OpenResty安装目录下的nginx的目录，然后让配置生效：</p></blockquote><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">source </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">etc</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">profile</span></span></code></pre></div><h3 id="启动和运行" tabindex="-1">启动和运行 <a class="header-anchor" href="#启动和运行" aria-label="Permalink to &quot;启动和运行&quot;">​</a></h3><blockquote><p>OpenResty底层是基于Nginx的，查看OpenResty目录的nginx目录，结构与windows中安装的nginx基本一致：所以运行方式与nginx基本一致：</p></blockquote><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;"># 启动nginx</span></span>
<span class="line"><span style="color:#FFCB6B;">nginx</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 重新加载配置</span></span>
<span class="line"><span style="color:#FFCB6B;">nginx</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-s</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">reload</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 停止</span></span>
<span class="line"><span style="color:#FFCB6B;">nginx</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-s</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">stop</span></span></code></pre></div><blockquote><p>nginx的默认配置文件注释太多，影响后续我们的编辑，这里将nginx.conf中的注释部分删除，保留有效部分。修改<code>/usr/local/openresty/nginx/conf/nginx.conf</code>文件，内容如下：</p></blockquote><div class="language-nginx"><button title="Copy Code" class="copy"></button><span class="lang">nginx</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">#user  nobody;</span></span>
<span class="line"><span style="color:#89DDFF;">worker_processes </span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#89DDFF;">error_log </span><span style="color:#A6ACCD;"> logs/error.log</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#C792EA;">events</span><span style="color:#A6ACCD;"> {</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#89DDFF;"> worker_connections </span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1024</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#C792EA;">http</span><span style="color:#A6ACCD;"> {</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#89DDFF;"> include </span><span style="color:#A6ACCD;">      mime.types</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#89DDFF;"> default_type </span><span style="color:#A6ACCD;"> application/octet-stream</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#89DDFF;"> sendfile </span><span style="color:#A6ACCD;">      </span><span style="color:#89DDFF;"> on;</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#89DDFF;"> keepalive_timeout </span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">65</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">server</span><span style="color:#A6ACCD;"> {</span></span>
<span class="line"><span style="color:#A6ACCD;">       </span><span style="color:#89DDFF;"> listen </span><span style="color:#A6ACCD;">      </span><span style="color:#F78C6C;">8081</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">       </span><span style="color:#89DDFF;"> server_name </span><span style="color:#A6ACCD;"> localhost</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">location</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">/ </span><span style="color:#A6ACCD;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">           </span><span style="color:#89DDFF;"> root </span><span style="color:#A6ACCD;">  html</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">           </span><span style="color:#89DDFF;"> index </span><span style="color:#A6ACCD;"> index.html index.htm</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">        }</span></span>
<span class="line"><span style="color:#A6ACCD;">       </span><span style="color:#89DDFF;"> error_page </span><span style="color:#A6ACCD;">  </span><span style="color:#F78C6C;">500</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">502</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">503</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">504</span><span style="color:#A6ACCD;">  /50x.html</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">location</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/50x.html </span><span style="color:#A6ACCD;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">           </span><span style="color:#89DDFF;"> root </span><span style="color:#A6ACCD;">  html</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">        }</span></span>
<span class="line"><span style="color:#A6ACCD;">    }</span></span>
<span class="line"><span style="color:#A6ACCD;">}</span></span></code></pre></div><p>在Linux的控制台输入命令以启动nginx：</p><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#FFCB6B;">nginx</span></span>
<span class="line"><span style="color:#FFCB6B;">nginx</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-s</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">reload</span></span></code></pre></div><p>然后访问页面：<a href="http://192.168.88.101:8081" target="_blank" rel="noreferrer">http://192.168.88.101:8081</a>，注意ip地址替换为你自己的虚拟机IP：</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;"># 改名</span></span>
<span class="line"><span style="color:#A6ACCD;">mv nginx.conf nginxOld.conf </span></span>
<span class="line"><span style="color:#A6ACCD;"># 复制</span></span>
<span class="line"><span style="color:#A6ACCD;">cp nginx.conf.default nginx.conf  </span></span>
<span class="line"><span style="color:#A6ACCD;">nginx</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209161625270.png" alt="image-20220916162513152" style="zoom:80%;"><h3 id="快速入门" tabindex="-1">快速入门 <a class="header-anchor" href="#快速入门" aria-label="Permalink to &quot;快速入门&quot;">​</a></h3><p>我们希望达到的多级缓存架构如图：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/yeVDlwtfMx.png" alt="yeVDlwtfMx" style="zoom:80%;"><blockquote><p>OpenResty的很多功能都依赖于其目录下的Lua库，需要在nginx.conf中指定依赖库的目录</p><p>修改<code>/usr/local/openresty/nginx/conf/nginx.conf</code>文件,添加lua模块和返回内容</p></blockquote><div class="language-nginx"><button title="Copy Code" class="copy"></button><span class="lang">nginx</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">#user  nobody;</span></span>
<span class="line"><span style="color:#89DDFF;">worker_processes </span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#89DDFF;">error_log </span><span style="color:#A6ACCD;"> logs/error.log</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#C792EA;">events</span><span style="color:#A6ACCD;"> {</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#89DDFF;"> worker_connections </span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1024</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#C792EA;">http</span><span style="color:#A6ACCD;"> {</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#89DDFF;"> include </span><span style="color:#A6ACCD;">      mime.types</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#89DDFF;"> default_type </span><span style="color:#A6ACCD;"> application/octet-stream</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#89DDFF;"> sendfile </span><span style="color:#A6ACCD;">      </span><span style="color:#89DDFF;"> on;</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#89DDFF;"> keepalive_timeout </span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">65</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#676E95;font-style:italic;"># 加载lua 模块，.lua结尾的就是lua模块</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">lua_package_path</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">&quot;/usr/local/openresty/lualib/?.lua;;&quot;</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#676E95;font-style:italic;"># 加载c模块 ，.so结尾的就是c模块    </span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">lua_package_cpath</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">&quot;/usr/local/openresty/lualib/?.so;;&quot;</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;">  </span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">server</span><span style="color:#A6ACCD;"> {</span></span>
<span class="line"><span style="color:#A6ACCD;">       </span><span style="color:#89DDFF;"> listen </span><span style="color:#A6ACCD;">      </span><span style="color:#F78C6C;">8081</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">       </span><span style="color:#89DDFF;"> server_name </span><span style="color:#A6ACCD;"> localhost</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#676E95;font-style:italic;"># 设置响应结果</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">location</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">/api/item </span><span style="color:#A6ACCD;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#676E95;font-style:italic;"># 默认的响应类型</span></span>
<span class="line"><span style="color:#A6ACCD;">           </span><span style="color:#89DDFF;"> default_type </span><span style="color:#A6ACCD;">  application/json</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#676E95;font-style:italic;"># 响应结果由lua/item.lua文件来决定</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">content_by_lua_file</span><span style="color:#A6ACCD;">  lua/item.lua</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">        }</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">location</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">/ </span><span style="color:#A6ACCD;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">           </span><span style="color:#89DDFF;"> root </span><span style="color:#A6ACCD;">  html</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">           </span><span style="color:#89DDFF;"> index </span><span style="color:#A6ACCD;"> index.html index.htm</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">        }</span></span>
<span class="line"><span style="color:#A6ACCD;">       </span><span style="color:#89DDFF;"> error_page </span><span style="color:#A6ACCD;">  </span><span style="color:#F78C6C;">500</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">502</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">503</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">504</span><span style="color:#A6ACCD;">  /50x.html</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">location</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/50x.html </span><span style="color:#A6ACCD;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">           </span><span style="color:#89DDFF;"> root </span><span style="color:#A6ACCD;">  html</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">        }</span></span>
<span class="line"><span style="color:#A6ACCD;">    }</span></span>
<span class="line"><span style="color:#A6ACCD;">}</span></span></code></pre></div><blockquote><p>创建lua/item.lua，在<code>/usr/local/openresty/nginx</code>目录创建文件夹：lua，新建文件：item.lua</p></blockquote><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">mkdir lua</span></span>
<span class="line"><span style="color:#A6ACCD;">cd lua</span></span>
<span class="line"><span style="color:#A6ACCD;">touch item.lua</span></span></code></pre></div><blockquote><p>编写item.lua，返回假数据item.lua中，利用ngx.say()函数返回数据到Response中，里面就是JSON对象</p></blockquote><div class="language-lua"><button title="Copy Code" class="copy"></button><span class="lang">lua</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">ngx.</span><span style="color:#82AAFF;">say</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">{&quot;id&quot;:10001,&quot;name&quot;:&quot;SALSA AIR&quot;,&quot;title&quot;:&quot;RIMOWA 21寸托运箱拉杆箱 SALSA AIR系列果绿色 820.70.36.4&quot;,&quot;price&quot;:17900,&quot;image&quot;:&quot;https://m.360buyimg.com/mobilecms/s720x720_jfs/t6934/364/1195375010/84676/e9f2c55f/597ece38N0ddcbc77.jpg!q70.jpg.webp&quot;,&quot;category&quot;:&quot;拉杆箱&quot;,&quot;brand&quot;:&quot;RIMOWA&quot;,&quot;spec&quot;:&quot;&quot;,&quot;status&quot;:1,&quot;createTime&quot;:&quot;2019-04-30T16:00:00.000+00:00&quot;,&quot;updateTime&quot;:&quot;2019-04-30T16:00:00.000+00:00&quot;,&quot;stock&quot;:2999,&quot;sold&quot;:31290}</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span></code></pre></div><blockquote><p>4）重新加载配置</p></blockquote><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#FFCB6B;">nginx</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-s</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">reload</span></span></code></pre></div><blockquote><p>测试访问，刷新商品页面：<a href="http://192.168.88.101:8081/api/item%EF%BC%8C%E5%8D%B3%E5%8F%AF%E7%9C%8B%E5%88%B0%E6%95%88%E6%9E%9C%EF%BC%9A" target="_blank" rel="noreferrer">http://192.168.88.101:8081/api/item，即可看到效果：</a></p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202306121953933.png" alt="image-20230612195307785" style="zoom:80%;"><h3 id="请求参数处理" tabindex="-1">请求参数处理 <a class="header-anchor" href="#请求参数处理" aria-label="Permalink to &quot;请求参数处理&quot;">​</a></h3><blockquote><p>上一节中，我们在OpenResty接收前端请求，但是返回的是假数据。要返回真实数据，必须根据前端传递来的商品id，查询商品信息才可以。<strong>那么如何获取前端传递的商品参数呢？</strong></p></blockquote><h4 id="基本语法" tabindex="-1">基本语法 <a class="header-anchor" href="#基本语法" aria-label="Permalink to &quot;基本语法&quot;">​</a></h4><blockquote><p>OpenResty中提供了一些API用来获取不同类型的前端请求参数：</p></blockquote><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20210821101433528.png" alt="image-20210821101433528"></p><h4 id="实战演练⭐" tabindex="-1">实战演练⭐ <a class="header-anchor" href="#实战演练⭐" aria-label="Permalink to &quot;实战演练⭐&quot;">​</a></h4><blockquote><p>在前端发起的ajax请求如图：</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20210821101721649.png" alt="image-20210821101721649" style="zoom:80%;"><blockquote><p>可以看到商品id是以路径占位符方式传递的，因此可以利用正则表达式匹配的方式来获取ID</p></blockquote><blockquote><p>1）获取商品id修改<code>/usr/loca/openresty/nginx/nginx.conf</code>，利用正则表达式获取ID：</p></blockquote><div class="language-nginx"><button title="Copy Code" class="copy"></button><span class="lang">nginx</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;"># ~表示后面是正则表达式,\d+表示一个或多个数字</span></span>
<span class="line"><span style="color:#C792EA;">location</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">~</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/api/item/(\d+) </span><span style="color:#A6ACCD;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#676E95;font-style:italic;"># 默认的响应类型</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#89DDFF;"> default_type </span><span style="color:#A6ACCD;">application/json</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#676E95;font-style:italic;"># 响应结果由lua/item.lua文件来决定</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">content_by_lua_file</span><span style="color:#A6ACCD;"> lua/item.lua</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">}</span></span></code></pre></div><blockquote><p>2）拼接ID并返回修改<code>/usr/loca/openresty/nginx/lua/item.lua</code>文件，<strong>获取id并拼接到结果</strong></p></blockquote><div class="language-lua"><button title="Copy Code" class="copy"></button><span class="lang">lua</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 获取商品id，匹配到的内容会放到数组中，通过数组拿内容</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> ngx.</span><span style="color:#FFCB6B;">var</span><span style="color:#A6ACCD;">[</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">]</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 拼接并返回：..表示lua语法拼接字符串</span></span>
<span class="line"><span style="color:#A6ACCD;">ngx.</span><span style="color:#82AAFF;">say</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">{&quot;id&quot;:</span><span style="color:#89DDFF;">&#39; </span><span style="color:#89DDFF;">..</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">..</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">,&quot;name&quot;:&quot;SALSA AIR&quot;,&quot;title&quot;:&quot;RIMOWA 21寸托运箱拉杆箱 SALSA AIR系列果绿色 820.70.36.4&quot;,&quot;price&quot;:17900,&quot;image&quot;:&quot;https://m.360buyimg.com/mobilecms/s720x720_jfs/t6934/364/1195375010/84676/e9f2c55f/597ece38N0ddcbc77.jpg!q70.jpg.webp&quot;,&quot;category&quot;:&quot;拉杆箱&quot;,&quot;brand&quot;:&quot;RIMOWA&quot;,&quot;spec&quot;:&quot;&quot;,&quot;status&quot;:1,&quot;createTime&quot;:&quot;2019-04-30T16:00:00.000+00:00&quot;,&quot;updateTime&quot;:&quot;2019-04-30T16:00:00.000+00:00&quot;,&quot;stock&quot;:2999,&quot;sold&quot;:31290}</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span></code></pre></div><blockquote><p>3）重新加载并测试,运行命令以重新加载OpenResty配置：</p></blockquote><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#FFCB6B;">nginx</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-s</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">reload</span></span></code></pre></div><blockquote><p>刷新页面可以看到结果中已经带上了ID：<a href="http://192.168.88.101:8081/api/item/102" target="_blank" rel="noreferrer">http://192.168.88.101:8081/api/item/102</a></p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202306122118166.png" alt="image-20230612211844031" style="zoom:67%;"><h3 id="前置知识" tabindex="-1">前置知识 <a class="header-anchor" href="#前置知识" aria-label="Permalink to &quot;前置知识&quot;">​</a></h3><h4 id="cjson工具类" tabindex="-1">CJSON工具类 <a class="header-anchor" href="#cjson工具类" aria-label="Permalink to &quot;CJSON工具类&quot;">​</a></h4><blockquote><p>OpenResty提供了一个cjson的模块用来处理JSON的序列化和反序列化。</p><p>官方地址： <a href="https://github.com/openresty/lua-cjson/" target="_blank" rel="noreferrer">https://github.com/openresty/lua-cjson/</a></p></blockquote><blockquote><p>1）引入cjson模块</p></blockquote><div class="language-lua"><button title="Copy Code" class="copy"></button><span class="lang">lua</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> cjson </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">require</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">cjson</span><span style="color:#89DDFF;">&quot;</span></span></code></pre></div><blockquote><p>2）序列化</p></blockquote><div class="language-lua"><button title="Copy Code" class="copy"></button><span class="lang">lua</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> obj </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> {</span></span>
<span class="line"><span style="color:#A6ACCD;">    name </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">jack</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">    age </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">21</span></span>
<span class="line"><span style="color:#A6ACCD;">}</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 把 table 序列化为 json</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> json </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> cjson.</span><span style="color:#82AAFF;">encode</span><span style="color:#A6ACCD;">(obj)</span></span></code></pre></div><blockquote><p>3）反序列化</p></blockquote><div class="language-lua"><button title="Copy Code" class="copy"></button><span class="lang">lua</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> json </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">{&quot;name&quot;: &quot;jack&quot;, &quot;age&quot;: 21}</span><span style="color:#89DDFF;">&#39;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 反序列化 json为 table</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> obj </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> cjson.</span><span style="color:#82AAFF;">decode</span><span style="color:#A6ACCD;">(json);</span></span>
<span class="line"><span style="color:#82AAFF;">print</span><span style="color:#A6ACCD;">(obj.</span><span style="color:#FFCB6B;">name</span><span style="color:#A6ACCD;">)</span></span></code></pre></div><h4 id="基于id负载均衡" tabindex="-1">基于ID负载均衡 <a class="header-anchor" href="#基于id负载均衡" aria-label="Permalink to &quot;基于ID负载均衡&quot;">​</a></h4><blockquote><p>刚才的代码中，我们的tomcat是单机部署。而实际开发中，tomcat一定是集群模式：</p></blockquote><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20210821111023255.png" alt="image-20210821111023255"></p><blockquote><p>因此，OpenResty需要对tomcat集群做负载均衡。而默认的负载均衡规则是轮询模式，当我们查询/item/10001时：</p></blockquote><blockquote><ul><li>第一次会访问8081端口的tomcat服务，在该服务内部就形成了JVM进程缓存</li><li>第二次会访问8082端口的tomcat服务，该服务内部没有JVM缓存（因为JVM缓存无法共享）</li></ul></blockquote><blockquote><p>你看，因为轮询的原因，第一次查询8081形成的JVM缓存并未生效，直到下一次再次访问到8081时才可以生效，缓存命中率太低了。怎么办？如果能让同一个商品，每次查询时都访问同一个tomcat服务，那么JVM缓存就一定能生效了。也就是说，我们需要根据商品id做负载均衡，而不是轮询。</p></blockquote><blockquote><p>1）原理nginx提供了基于请求路径做负载均衡的算法：</p></blockquote><blockquote><p>nginx根据请求路径做hash运算，把得到的数值对tomcat服务的数量取余，余数是几，就访问第几个服务，实现负载均衡。例如：</p></blockquote><ul><li>我们的请求路径是 /item/10001</li><li>tomcat总数为2台（8081、8082）</li><li>对请求路径/item/1001做hash运算求余的结果为1</li><li>则访问第一个tomcat服务，也就是8081</li></ul><p>只要id不变，每次hash运算结果也不会变，那就可以保证同一个商品，一直访问同一个tomcat服务，确保JVM缓存生效。</p><blockquote><p>2）实现修改<code>/usr/local/openresty/nginx/conf/nginx.conf</code>文件，实现基于ID做负载均衡。</p></blockquote><p>首先，定义tomcat集群，并设置基于路径做负载均衡：</p><div class="language-nginx"><button title="Copy Code" class="copy"></button><span class="lang">nginx</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">upstream</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">tomcat-cluster </span><span style="color:#A6ACCD;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#89DDFF;"> hash $</span><span style="color:#A6ACCD;">request_uri</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">server</span><span style="color:#A6ACCD;"> 192.168.0.155:8081;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">server</span><span style="color:#A6ACCD;"> 192.168.0.155:8082;</span></span>
<span class="line"><span style="color:#A6ACCD;">}</span></span></code></pre></div><p>然后，修改对tomcat服务的反向代理，目标指向tomcat集群：</p><div class="language-nginx"><button title="Copy Code" class="copy"></button><span class="lang">nginx</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">location</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">/item </span><span style="color:#A6ACCD;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#89DDFF;"> proxy_pass </span><span style="color:#A6ACCD;">http://tomcat-cluster</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">}</span></span></code></pre></div><p>重新加载OpenResty</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">nginx </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">s reload</span></span></code></pre></div><blockquote><p>3）测试启动两台tomcat服务：</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20210821112420464.png" alt="image-20210821112420464" style="zoom:80%;"><p>同时启动：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20210821112444482.png" alt="image-20210821112444482" style="zoom:80%;"><p>清空日志后，再次访问页面，可以看到不同id的商品，访问到了不同的tomcat服务：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20210821112559965.png" alt="image-20210821112559965" style="zoom:80%;"><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20210821112637430.png" alt="image-20210821112637430"></p><h3 id="实战演练⭐-1" tabindex="-1">实战演练⭐ <a class="header-anchor" href="#实战演练⭐-1" aria-label="Permalink to &quot;实战演练⭐&quot;">​</a></h3><blockquote><p>拿到商品ID后，本应去缓存中查询商品信息，不过目前我们还未建立nginx、redis缓存。因此，这里我们先根据商品id去tomcat查询商品信息。我们实现如图部分：</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20210821102610167.png" alt="image-20210821102610167" style="zoom:67%;"><p>这里要修改item.lua，满足下面的需求：</p><blockquote><p>1.获取请求参数中的id</p><p>2.根据id向Tomcat服务发送请求，查询商品信息</p><p>3.根据id向Tomcat服务发送请求，查询库存信息</p><p>4.组装商品信息、库存信息，序列化为JSON格式并返回</p></blockquote><h4 id="common-lua⭐" tabindex="-1">common.lua⭐ <a class="header-anchor" href="#common-lua⭐" aria-label="Permalink to &quot;common.lua⭐&quot;">​</a></h4><blockquote><p>在<code>/usr/local/openresty/lualib</code>目录下，新建一个common.lua文件</p></blockquote><div class="language-lua"><button title="Copy Code" class="copy"></button><span class="lang">lua</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 封装函数，发送http请求，并解析响应</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">function</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">read_http</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;font-style:italic;">path</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">params</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> resp </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> ngx.</span><span style="color:#FFCB6B;">location</span><span style="color:#A6ACCD;">.</span><span style="color:#82AAFF;">capture</span><span style="color:#A6ACCD;">(path,{</span></span>
<span class="line"><span style="color:#A6ACCD;">        method </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> ngx.</span><span style="color:#FFCB6B;">HTTP_GET</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">        args </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> params,</span></span>
<span class="line"><span style="color:#A6ACCD;">    })</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">not</span><span style="color:#A6ACCD;"> resp </span><span style="color:#89DDFF;font-style:italic;">then</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">-- 记录错误信息，返回404</span></span>
<span class="line"><span style="color:#A6ACCD;">        ngx.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(ngx.</span><span style="color:#FFCB6B;">ERR</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">http请求查询失败, path: </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, path , </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">, args: </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, args)</span></span>
<span class="line"><span style="color:#A6ACCD;">        ngx.</span><span style="color:#82AAFF;">exit</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">404</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> resp.</span><span style="color:#FFCB6B;">body</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 将方法导出</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> _M </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> {  </span></span>
<span class="line"><span style="color:#A6ACCD;">    read_http </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> read_http</span></span>
<span class="line"><span style="color:#A6ACCD;">}  </span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> _M</span></span></code></pre></div><h4 id="item-lua" tabindex="-1">item.lua <a class="header-anchor" href="#item-lua" aria-label="Permalink to &quot;item.lua&quot;">​</a></h4><blockquote><p>下面，我们修改之前的/usr/local/openresty/nginx/lua/item.lua中的业务，添加json处理功能：这里查询到的结果是json字符串，并且包含商品、库存两个json字符串，页面需要的是把两个json拼接为一个</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20210821110441222.png" alt="image-20210821110441222" style="zoom:80%;"><p>这就需要我们先把JSON变为lua的table，完成数据整合后，再转为JSON。</p><div class="language-lua"><button title="Copy Code" class="copy"></button><span class="lang">lua</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 导入common，是common.lua的名字</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> common </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">require</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">common</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> read_http </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> common.</span><span style="color:#FFCB6B;">read_http</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 导入cjson库</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> cjson </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">require</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">cjson</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 获取路径参数</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> ngx.</span><span style="color:#FFCB6B;">var</span><span style="color:#A6ACCD;">[</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">]</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 根据id查询商品</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> itemJSON </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">read_http</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">/item/</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">..</span><span style="color:#A6ACCD;"> id, </span><span style="color:#89DDFF;">nil</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 根据id查询商品库存</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> itemStockJSON </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">read_http</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">/item/stock/</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">..</span><span style="color:#A6ACCD;"> id, </span><span style="color:#89DDFF;">nil</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- JSON转化为lua的table</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> item </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> cjson.</span><span style="color:#82AAFF;">decode</span><span style="color:#A6ACCD;">(itemJSON)</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> stock </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> cjson.</span><span style="color:#82AAFF;">decode</span><span style="color:#A6ACCD;">(itemStockJSON)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 组合数据</span></span>
<span class="line"><span style="color:#A6ACCD;">item.</span><span style="color:#FFCB6B;">stock</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> stock.</span><span style="color:#FFCB6B;">stock</span></span>
<span class="line"><span style="color:#A6ACCD;">item.</span><span style="color:#FFCB6B;">sold</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> stock.</span><span style="color:#FFCB6B;">sold</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 把item序列化为json 返回结果</span></span>
<span class="line"><span style="color:#A6ACCD;">ngx.</span><span style="color:#82AAFF;">say</span><span style="color:#A6ACCD;">(cjson.</span><span style="color:#82AAFF;">encode</span><span style="color:#A6ACCD;">(item))</span></span></code></pre></div><h4 id="nginx-conf" tabindex="-1">nginx.conf <a class="header-anchor" href="#nginx-conf" aria-label="Permalink to &quot;nginx.conf&quot;">​</a></h4><p>首先，在http块定义tomcat集群，并设置基于路径做负载均衡：</p><div class="language-nginx"><button title="Copy Code" class="copy"></button><span class="lang">nginx</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">upstream</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">tomcat-cluster </span><span style="color:#A6ACCD;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#89DDFF;"> hash $</span><span style="color:#A6ACCD;">request_uri</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">server</span><span style="color:#A6ACCD;"> 192.168.0.155:8081;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">server</span><span style="color:#A6ACCD;"> 192.168.0.155:8082;</span></span>
<span class="line"><span style="color:#A6ACCD;">}</span></span></code></pre></div><p>然后，修改对tomcat服务的反向代理，目标指向tomcat集群：</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">location </span><span style="color:#89DDFF;">~</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">api</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">item</span><span style="color:#89DDFF;">/(\</span><span style="color:#A6ACCD;">d</span><span style="color:#89DDFF;">+)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 默认的响应类型</span></span>
<span class="line"><span style="color:#A6ACCD;">    default_type application</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">json</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 响应结果由lua</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">item</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">lua文件来决定</span></span>
<span class="line"><span style="color:#A6ACCD;">    content_by_lua_file lua</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">item</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">lua</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 启动后端服务</span></span>
<span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 注意：这边写成</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">item原因是真正发起请求的是item</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">lua，他两个请求都是</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">item开头，因此不用写成</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">api</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">item</span></span>
<span class="line"><span style="color:#A6ACCD;">location </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">item </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 反向代理</span></span>
<span class="line"><span style="color:#A6ACCD;">   proxy_pass http:</span><span style="color:#89DDFF;">//</span><span style="color:#A6ACCD;">tomcat</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">cluster</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;">  </span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><p>重新加载OpenResty</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">nginx </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">s reload</span></span></code></pre></div><h4 id="访问测试-1" tabindex="-1">访问测试 <a class="header-anchor" href="#访问测试-1" aria-label="Permalink to &quot;访问测试&quot;">​</a></h4><p>本地：<a href="http://192.168.0.155:8081/item/stock/10001" target="_blank" rel="noreferrer">http://192.168.0.155:8081/item/stock/10001</a></p><p>本地：<a href="http://192.168.0.155:8081/item/10001" target="_blank" rel="noreferrer">http://192.168.0.155:8081/item/10001</a></p><p>访问：<a href="http://192.168.22.145:8081/api/item/10003%EF%BC%8C%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%88%B0%E4%B8%A4%E4%B8%AA%E7%BB%93%E6%9E%9C%E8%A2%AB%E6%8B%BC%E6%8E%A5%E8%B5%B7%E6%9D%A5%E4%BA%86" target="_blank" rel="noreferrer">http://192.168.22.145:8081/api/item/10003，可以看到两个结果被拼接起来了</a></p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209171040350.png" alt="image-20220917104052207" style="zoom:80%;"><h2 id="nginx查询redis缓存" tabindex="-1">Nginx查询Redis缓存 <a class="header-anchor" href="#nginx查询redis缓存" aria-label="Permalink to &quot;Nginx查询Redis缓存&quot;">​</a></h2><p>现在，Redis缓存已经准备就绪，我们可以再OpenResty中实现查询Redis的逻辑了。如下图红框所示：</p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20210821113340111.png" alt="image-20210821113340111"></p><p>当请求进入OpenResty之后：</p><ul><li>优先查询Redis缓存</li><li>如果Redis缓存未命中，再查询Tomcat</li></ul><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.11/202206091228990.png" alt="image-20220609122826914" style="zoom:80%;"><h3 id="封装redis工具" tabindex="-1">封装Redis工具 <a class="header-anchor" href="#封装redis工具" aria-label="Permalink to &quot;封装Redis工具&quot;">​</a></h3><blockquote><p>OpenResty提供了操作Redis的模块，我们只要引入该模块就能直接使用。但是为了方便，我们将Redis操作封装到之前的common.lua工具库中。修改<code>/usr/local/openresty/lualib/common.lua</code>文件</p></blockquote><blockquote><p>1）引入Redis模块，并初始化Redis对象</p></blockquote><div class="language-lua"><button title="Copy Code" class="copy"></button><span class="lang">lua</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 导入redis</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> redis </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">require</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">resty.redis</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 初始化redis</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> red </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">redis</span><span style="color:#A6ACCD;">:</span><span style="color:#82AAFF;">new</span><span style="color:#A6ACCD;">()</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 建立连接、发送请求、响应结果的超时时间，单位毫秒</span></span>
<span class="line"><span style="color:#FFCB6B;">red</span><span style="color:#A6ACCD;">:</span><span style="color:#82AAFF;">set_timeouts</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">1000</span><span style="color:#A6ACCD;">, </span><span style="color:#F78C6C;">1000</span><span style="color:#A6ACCD;">, </span><span style="color:#F78C6C;">1000</span><span style="color:#A6ACCD;">)</span></span></code></pre></div><blockquote><p>2）封装函数，用来释放Redis连接，其实是放入连接池</p></blockquote><div class="language-lua"><button title="Copy Code" class="copy"></button><span class="lang">lua</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 关闭redis连接的工具方法，其实是放入连接池</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">function</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">close_redis</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;font-style:italic;">red</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> pool_max_idle_time </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">10000</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;">-- 连接的空闲时间，单位是毫秒</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> pool_size </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">100</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;">--连接池大小</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> ok, err </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">red</span><span style="color:#A6ACCD;">:</span><span style="color:#82AAFF;">set_keepalive</span><span style="color:#A6ACCD;">(pool_max_idle_time, pool_size)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">not</span><span style="color:#A6ACCD;"> ok </span><span style="color:#89DDFF;font-style:italic;">then</span></span>
<span class="line"><span style="color:#A6ACCD;">        ngx.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(ngx.</span><span style="color:#FFCB6B;">ERR</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">放入redis连接池失败: </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, err)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">end</span></span></code></pre></div><blockquote><p>3）封装函数，根据key查询Redis数据</p></blockquote><div class="language-lua"><button title="Copy Code" class="copy"></button><span class="lang">lua</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 查询redis的方法 ip和port是redis地址，key是查询的key</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">function</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">read_redis</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;font-style:italic;">ip</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">port</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">key</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 获取一个连接</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> ok, err </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">red</span><span style="color:#A6ACCD;">:</span><span style="color:#82AAFF;">connect</span><span style="color:#A6ACCD;">(ip, port)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">not</span><span style="color:#A6ACCD;"> ok </span><span style="color:#89DDFF;font-style:italic;">then</span></span>
<span class="line"><span style="color:#A6ACCD;">        ngx.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(ngx.</span><span style="color:#FFCB6B;">ERR</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">连接redis失败 : </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, err)</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">nil</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 查询redis</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> resp, err </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">red</span><span style="color:#A6ACCD;">:</span><span style="color:#82AAFF;">get</span><span style="color:#A6ACCD;">(key)</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 查询失败处理</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">not</span><span style="color:#A6ACCD;"> resp </span><span style="color:#89DDFF;font-style:italic;">then</span></span>
<span class="line"><span style="color:#A6ACCD;">        ngx.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(ngx.</span><span style="color:#FFCB6B;">ERR</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">查询Redis失败: </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, err, </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">, key = </span><span style="color:#89DDFF;">&quot; </span><span style="color:#A6ACCD;">, key)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">--得到的数据为空处理</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> resp </span><span style="color:#89DDFF;">==</span><span style="color:#A6ACCD;"> ngx.</span><span style="color:#FFCB6B;">null</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">then</span></span>
<span class="line"><span style="color:#A6ACCD;">        resp </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">nil</span></span>
<span class="line"><span style="color:#A6ACCD;">        ngx.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(ngx.</span><span style="color:#FFCB6B;">ERR</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">查询Redis数据为空, key = </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, key)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#82AAFF;">close_redis</span><span style="color:#A6ACCD;">(red)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> resp</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">end</span></span></code></pre></div><blockquote><p>4）导出</p></blockquote><div class="language-lua"><button title="Copy Code" class="copy"></button><span class="lang">lua</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 将方法导出</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> _M </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> {  </span></span>
<span class="line"><span style="color:#A6ACCD;">    read_http </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> read_http,</span></span>
<span class="line"><span style="color:#A6ACCD;">    read_redis </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> read_redis</span></span>
<span class="line"><span style="color:#A6ACCD;">}  </span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> _M</span></span></code></pre></div><blockquote><p>/usr/local/openresty/lualib/common.lua完整代码</p></blockquote><div class="language-lua"><button title="Copy Code" class="copy"></button><span class="lang">lua</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 导入redis</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> redis </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">require</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">resty.redis</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 初始化redis</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> red </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">redis</span><span style="color:#A6ACCD;">:</span><span style="color:#82AAFF;">new</span><span style="color:#A6ACCD;">()</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 分别对应建立连接、发送请求、响应结果的超时时间</span></span>
<span class="line"><span style="color:#FFCB6B;">red</span><span style="color:#A6ACCD;">:</span><span style="color:#82AAFF;">set_timeouts</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">1000</span><span style="color:#A6ACCD;">, </span><span style="color:#F78C6C;">1000</span><span style="color:#A6ACCD;">, </span><span style="color:#F78C6C;">1000</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 关闭redis连接的工具方法，其实是放入连接池</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">function</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">close_redis</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;font-style:italic;">red</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> pool_max_idle_time </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">10000</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;">-- 连接的空闲时间，单位是毫秒</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> pool_size </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">100</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;">--连接池大小</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> ok, err </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">red</span><span style="color:#A6ACCD;">:</span><span style="color:#82AAFF;">set_keepalive</span><span style="color:#A6ACCD;">(pool_max_idle_time, pool_size)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">not</span><span style="color:#A6ACCD;"> ok </span><span style="color:#89DDFF;font-style:italic;">then</span></span>
<span class="line"><span style="color:#A6ACCD;">        ngx.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(ngx.</span><span style="color:#FFCB6B;">ERR</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">放入redis连接池失败: </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, err)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 查询redis的方法 ip和port是redis地址，key是查询的key</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">function</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">read_redis</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;font-style:italic;">ip</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">port</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">key</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 获取一个连接</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> ok, err </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">red</span><span style="color:#A6ACCD;">:</span><span style="color:#82AAFF;">connect</span><span style="color:#A6ACCD;">(ip, port)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">not</span><span style="color:#A6ACCD;"> ok </span><span style="color:#89DDFF;font-style:italic;">then</span></span>
<span class="line"><span style="color:#A6ACCD;">        ngx.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(ngx.</span><span style="color:#FFCB6B;">ERR</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">连接redis失败 : </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, err)</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">nil</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 查询redis</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> resp, err </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">red</span><span style="color:#A6ACCD;">:</span><span style="color:#82AAFF;">get</span><span style="color:#A6ACCD;">(key)</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 查询失败处理</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">not</span><span style="color:#A6ACCD;"> resp </span><span style="color:#89DDFF;font-style:italic;">then</span></span>
<span class="line"><span style="color:#A6ACCD;">        ngx.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(ngx.</span><span style="color:#FFCB6B;">ERR</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">查询Redis失败: </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, err, </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">, key = </span><span style="color:#89DDFF;">&quot; </span><span style="color:#A6ACCD;">, key)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">--得到的数据为空处理</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> resp </span><span style="color:#89DDFF;">==</span><span style="color:#A6ACCD;"> ngx.</span><span style="color:#FFCB6B;">null</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">then</span></span>
<span class="line"><span style="color:#A6ACCD;">        resp </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">nil</span></span>
<span class="line"><span style="color:#A6ACCD;">        ngx.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(ngx.</span><span style="color:#FFCB6B;">ERR</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">查询Redis数据为空, key = </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, key)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#82AAFF;">close_redis</span><span style="color:#A6ACCD;">(red)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> resp</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 封装函数，发送http请求，并解析响应</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">function</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">read_http</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;font-style:italic;">path</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">params</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> resp </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> ngx.</span><span style="color:#FFCB6B;">location</span><span style="color:#A6ACCD;">.</span><span style="color:#82AAFF;">capture</span><span style="color:#A6ACCD;">(path,{</span></span>
<span class="line"><span style="color:#A6ACCD;">        method </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> ngx.</span><span style="color:#FFCB6B;">HTTP_GET</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">        args </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> params,</span></span>
<span class="line"><span style="color:#A6ACCD;">    })</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">not</span><span style="color:#A6ACCD;"> resp </span><span style="color:#89DDFF;font-style:italic;">then</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">-- 记录错误信息，返回404</span></span>
<span class="line"><span style="color:#A6ACCD;">        ngx.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(ngx.</span><span style="color:#FFCB6B;">ERR</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">http查询失败, path: </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, path , </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">, args: </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, args)</span></span>
<span class="line"><span style="color:#A6ACCD;">        ngx.</span><span style="color:#82AAFF;">exit</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">404</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> resp.</span><span style="color:#FFCB6B;">body</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 将方法导出</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> _M </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> {  </span></span>
<span class="line"><span style="color:#A6ACCD;">    read_http </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> read_http,</span></span>
<span class="line"><span style="color:#A6ACCD;">    read_redis </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> read_redis</span></span>
<span class="line"><span style="color:#A6ACCD;">}  </span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> _M</span></span></code></pre></div><h3 id="实现redis查询" tabindex="-1">实现Redis查询 <a class="header-anchor" href="#实现redis查询" aria-label="Permalink to &quot;实现Redis查询&quot;">​</a></h3><p>接下来，我们就可以去修改item.lua文件，实现对Redis的查询了，查询逻辑是：</p><blockquote><ul><li>根据id查询Redis</li><li>如果查询失败则继续查询Tomcat</li><li>将查询结果返回</li></ul></blockquote><blockquote><p>1）修改<code>/usr/local/openresty/lua/item.lua</code>文件，添加一个查询函数：</p></blockquote><div class="language-lua"><button title="Copy Code" class="copy"></button><span class="lang">lua</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 导入common函数库</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> common </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">require</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">common</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> read_http </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> common.</span><span style="color:#FFCB6B;">read_http</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> read_redis </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> common.</span><span style="color:#FFCB6B;">read_redis</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 封装查询函数</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">function</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">read_data</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;font-style:italic;">key</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">path</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">params</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 查询本地缓存</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> val </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">read_redis</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">127.0.0.1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, </span><span style="color:#F78C6C;">6379</span><span style="color:#A6ACCD;">, key)</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 判断查询结果</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">not</span><span style="color:#A6ACCD;"> val </span><span style="color:#89DDFF;font-style:italic;">then</span></span>
<span class="line"><span style="color:#A6ACCD;">        ngx.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(ngx.</span><span style="color:#FFCB6B;">ERR</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">redis查询失败，尝试查询http， key: </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, key)</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">-- redis查询失败，去查询http</span></span>
<span class="line"><span style="color:#A6ACCD;">        val </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">read_http</span><span style="color:#A6ACCD;">(path, params)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 返回数据</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> val</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">end</span></span></code></pre></div><blockquote><p>2）而后修改商品查询、库存查询的业务：</p></blockquote><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20210821114528954.png" alt="image-20210821114528954"></p><blockquote><p>nginx/lua/item.lua完整代码</p></blockquote><div class="language-lua"><button title="Copy Code" class="copy"></button><span class="lang">lua</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 导入common函数库</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> common </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">require</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">common</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> read_http </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> common.</span><span style="color:#FFCB6B;">read_http</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> read_redis </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> common.</span><span style="color:#FFCB6B;">read_redis</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 导入cjson库</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> cjson </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">require</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">cjson</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 封装查询函数</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">function</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">read_data</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;font-style:italic;">key</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">path</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">params</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 查询本地缓存</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> val </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">read_redis</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">127.0.0.1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, </span><span style="color:#F78C6C;">6379</span><span style="color:#A6ACCD;">, key)</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 判断查询结果</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">not</span><span style="color:#A6ACCD;"> val </span><span style="color:#89DDFF;font-style:italic;">then</span></span>
<span class="line"><span style="color:#A6ACCD;">        ngx.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(ngx.</span><span style="color:#FFCB6B;">ERR</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">redis查询失败，尝试查询http， key: </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, key)</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">-- redis查询失败，去查询http</span></span>
<span class="line"><span style="color:#A6ACCD;">        val </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">read_http</span><span style="color:#A6ACCD;">(path, params)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 返回数据</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> val</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 获取路径参数</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> ngx.</span><span style="color:#FFCB6B;">var</span><span style="color:#A6ACCD;">[</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 查询商品信息</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> itemJSON </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">read_data</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">item:id:</span><span style="color:#89DDFF;">&quot; </span><span style="color:#89DDFF;">..</span><span style="color:#A6ACCD;"> id,  </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">/item/</span><span style="color:#89DDFF;">&quot; </span><span style="color:#89DDFF;">..</span><span style="color:#A6ACCD;"> id, </span><span style="color:#89DDFF;">nil</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 查询库存信息</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> stockJSON </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">read_data</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">item:stock:id:</span><span style="color:#89DDFF;">&quot; </span><span style="color:#89DDFF;">..</span><span style="color:#A6ACCD;"> id, </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">/item/stock/</span><span style="color:#89DDFF;">&quot; </span><span style="color:#89DDFF;">..</span><span style="color:#A6ACCD;"> id, </span><span style="color:#89DDFF;">nil</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- JSON转化为lua的table</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> item </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> cjson.</span><span style="color:#82AAFF;">decode</span><span style="color:#A6ACCD;">(itemJSON)</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> stock </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> cjson.</span><span style="color:#82AAFF;">decode</span><span style="color:#A6ACCD;">(stockJSON)</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 组合数据</span></span>
<span class="line"><span style="color:#A6ACCD;">item.</span><span style="color:#FFCB6B;">stock</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> stock.</span><span style="color:#FFCB6B;">stock</span></span>
<span class="line"><span style="color:#A6ACCD;">item.</span><span style="color:#FFCB6B;">sold</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> stock.</span><span style="color:#FFCB6B;">sold</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 把item序列化为json 返回结果</span></span>
<span class="line"><span style="color:#A6ACCD;">ngx.</span><span style="color:#82AAFF;">say</span><span style="color:#A6ACCD;">(cjson.</span><span style="color:#82AAFF;">encode</span><span style="color:#A6ACCD;">(item))</span></span></code></pre></div><h3 id="查询调用" tabindex="-1">查询调用 <a class="header-anchor" href="#查询调用" aria-label="Permalink to &quot;查询调用&quot;">​</a></h3><blockquote><p>nginx.conf：和之前一样，并没有改变</p></blockquote><div class="language-nginx"><button title="Copy Code" class="copy"></button><span class="lang">nginx</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">upstream</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">tomcat-cluster </span><span style="color:#A6ACCD;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#89DDFF;"> hash $</span><span style="color:#A6ACCD;">request_uri</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">server</span><span style="color:#A6ACCD;"> 192.168.31.112:8081;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">server</span><span style="color:#A6ACCD;"> 192.168.31.112:8082;</span></span>
<span class="line"><span style="color:#A6ACCD;">}</span></span></code></pre></div><div class="language-nginx"><button title="Copy Code" class="copy"></button><span class="lang">nginx</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">location</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">/item </span><span style="color:#A6ACCD;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#89DDFF;"> proxy_pass </span><span style="color:#A6ACCD;">http://tomcat-cluster</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># ~表示后面是正则表达式,\d+表示一个或多个数字</span></span>
<span class="line"><span style="color:#C792EA;">location</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">~</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/api/item/(\d+) </span><span style="color:#A6ACCD;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#676E95;font-style:italic;"># 默认的响应类型</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#89DDFF;"> default_type </span><span style="color:#A6ACCD;">application/json</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#676E95;font-style:italic;"># 响应结果由lua/item.lua文件来决定</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">content_by_lua_file</span><span style="color:#A6ACCD;"> lua/item.lua</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">}</span></span></code></pre></div><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#FFCB6B;">nginx</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-s</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">reload</span></span></code></pre></div><blockquote><p>访问网址：<a href="http://192.168.88.101:8081/api/item/10001" target="_blank" rel="noreferrer">http://192.168.88.101:8081/api/item/10001</a></p></blockquote><blockquote><p>这样，只要数据存在redis中，即使服务器停机，我们依旧能从redis中获取数据</p></blockquote><h2 id="nginx本地缓存-完整实现" tabindex="-1">Nginx本地缓存(完整实现) <a class="header-anchor" href="#nginx本地缓存-完整实现" aria-label="Permalink to &quot;Nginx本地缓存(完整实现)&quot;">​</a></h2><blockquote><p>现在，整个多级缓存中只差最后一环，也就是nginx的本地缓存了。如图：</p></blockquote><blockquote><p>nginx本地缓存是采用时间过期策略，因此经常变化的数据就不要放在这里了</p></blockquote><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20210821114742950.png" alt="image-20210821114742950"></p><h3 id="本地缓存api" tabindex="-1">本地缓存API <a class="header-anchor" href="#本地缓存api" aria-label="Permalink to &quot;本地缓存API&quot;">​</a></h3><blockquote><p>OpenResty为Nginx提供了<strong>shard dict</strong>的功能，可以在nginx的多个worker之间共享数据，实现缓存功能</p></blockquote><blockquote><p>1）开启共享字典，在<strong>nginx.conf</strong>的http下添加配置：</p></blockquote><div class="language-nginx"><button title="Copy Code" class="copy"></button><span class="lang">nginx</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;"># 共享字典，也就是本地缓存，名称叫做：item_cache，大小150m</span></span>
<span class="line"><span style="color:#89DDFF;">lua_shared_dict</span><span style="color:#A6ACCD;"> item_cache </span><span style="color:#F78C6C;">150m</span><span style="color:#89DDFF;">;</span></span></code></pre></div><blockquote><p>2）操作共享字典</p></blockquote><div class="language-lua"><button title="Copy Code" class="copy"></button><span class="lang">lua</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 获取本地缓存对象</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> item_cache </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> ngx.</span><span style="color:#FFCB6B;">shared</span><span style="color:#A6ACCD;">.</span><span style="color:#FFCB6B;">item_cache</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 存储, 指定key、value、过期时间，单位s，默认为0代表永不过期</span></span>
<span class="line"><span style="color:#FFCB6B;">item_cache</span><span style="color:#A6ACCD;">:</span><span style="color:#82AAFF;">set</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">key</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">value</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">, </span><span style="color:#F78C6C;">1000</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 读取</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> val </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">item_cache</span><span style="color:#A6ACCD;">:</span><span style="color:#82AAFF;">get</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">key</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span></code></pre></div><h3 id="完整实现⭐" tabindex="-1">完整实现⭐ <a class="header-anchor" href="#完整实现⭐" aria-label="Permalink to &quot;完整实现⭐&quot;">​</a></h3><blockquote><p>这里把<strong>上面的Nginx查询接口+Redis+本地缓存结合到一起</strong></p></blockquote><blockquote><ol><li>修改item.lua中的read_data函数，优先查询本地缓存，未命中时再查询Redis、Tomcat</li><li>查询Redis或Tomcat成功后，将数据写入本地缓存，并设置有效期</li><li>商品基本信息，有效期30分钟</li><li>库存信息，有效期1分钟</li></ol></blockquote><h4 id="item-lua-1" tabindex="-1">item.lua <a class="header-anchor" href="#item-lua-1" aria-label="Permalink to &quot;item.lua&quot;">​</a></h4><h5 id="item-lua修改内容" tabindex="-1">item.lua修改内容 <a class="header-anchor" href="#item-lua修改内容" aria-label="Permalink to &quot;item.lua修改内容&quot;">​</a></h5><blockquote><p>1）修改<code>/usr/local/openresty/lua/item.lua</code>文件</p></blockquote><div class="language-lua"><button title="Copy Code" class="copy"></button><span class="lang">lua</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 导入共享词典，本地缓存</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> item_cache </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> ngx.</span><span style="color:#FFCB6B;">shared</span><span style="color:#A6ACCD;">.</span><span style="color:#FFCB6B;">item_cache</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 封装查询函数</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">function</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">read_data</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;font-style:italic;">key</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">expire</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">path</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">params</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 查询本地缓存</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> val </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">item_cache</span><span style="color:#A6ACCD;">:</span><span style="color:#82AAFF;">get</span><span style="color:#A6ACCD;">(key)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">not</span><span style="color:#A6ACCD;"> val </span><span style="color:#89DDFF;font-style:italic;">then</span></span>
<span class="line"><span style="color:#A6ACCD;">        ngx.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(ngx.</span><span style="color:#FFCB6B;">ERR</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">本地缓存查询失败，尝试查询Redis， key: </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, key)</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">-- 查询redis</span></span>
<span class="line"><span style="color:#A6ACCD;">        val </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">read_redis</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">127.0.0.1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, </span><span style="color:#F78C6C;">6379</span><span style="color:#A6ACCD;">, key)</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">-- 判断查询结果</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">not</span><span style="color:#A6ACCD;"> val </span><span style="color:#89DDFF;font-style:italic;">then</span></span>
<span class="line"><span style="color:#A6ACCD;">            ngx.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(ngx.</span><span style="color:#FFCB6B;">ERR</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">redis查询失败，尝试查询http， key: </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, key)</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">-- redis查询失败，去查询http</span></span>
<span class="line"><span style="color:#A6ACCD;">            val </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">read_http</span><span style="color:#A6ACCD;">(path, params)</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 查询成功，把数据写入本地缓存</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#FFCB6B;">item_cache</span><span style="color:#A6ACCD;">:</span><span style="color:#82AAFF;">set</span><span style="color:#A6ACCD;">(key, val, expire)</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 返回数据</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> val</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">end</span></span></code></pre></div><p>2）修改item.lua中查询商品和库存的业务，实现最新的read_data函数：</p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20210821115108528.png" alt="image-20210821115108528"></p><blockquote><p>其实就是多了缓存时间参数，过期后nginx缓存会自动删除，下次访问即可更新缓存。</p></blockquote><blockquote><p>这里给商品基本信息设置超时时间为30分钟，库存为1分钟。</p></blockquote><blockquote><p>因为库存更新频率较高，如果缓存时间过长，可能与数据库差异较大。</p></blockquote><h5 id="item-lua完整修改" tabindex="-1">item.lua完整修改 <a class="header-anchor" href="#item-lua完整修改" aria-label="Permalink to &quot;item.lua完整修改&quot;">​</a></h5><p>1）在<code>/usr/local/openresty/nginx/item.lua</code>，修改read_data查询函数，添加本地缓存逻辑：</p><div class="language-lua"><button title="Copy Code" class="copy"></button><span class="lang">lua</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 导入common函数库</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> common </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">require</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">common</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> read_http </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> common.</span><span style="color:#FFCB6B;">read_http</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> read_redis </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> common.</span><span style="color:#FFCB6B;">read_redis</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 导入cjson库</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> cjson </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">require</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">cjson</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 导入共享词典，本地缓存</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> item_cache </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> ngx.</span><span style="color:#FFCB6B;">shared</span><span style="color:#A6ACCD;">.</span><span style="color:#FFCB6B;">item_cache</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 封装查询函数</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">function</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">read_data</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;font-style:italic;">key</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">expire</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">path</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">params</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 查询本地缓存</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> val </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">item_cache</span><span style="color:#A6ACCD;">:</span><span style="color:#82AAFF;">get</span><span style="color:#A6ACCD;">(key)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">not</span><span style="color:#A6ACCD;"> val </span><span style="color:#89DDFF;font-style:italic;">then</span></span>
<span class="line"><span style="color:#A6ACCD;">        ngx.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(ngx.</span><span style="color:#FFCB6B;">ERR</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">本地缓存查询失败，尝试查询Redis， key: </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, key)</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">-- 查询redis</span></span>
<span class="line"><span style="color:#A6ACCD;">        val </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">read_redis</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">127.0.0.1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, </span><span style="color:#F78C6C;">6379</span><span style="color:#A6ACCD;">, key)</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">-- 判断查询结果</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">not</span><span style="color:#A6ACCD;"> val </span><span style="color:#89DDFF;font-style:italic;">then</span></span>
<span class="line"><span style="color:#A6ACCD;">            ngx.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(ngx.</span><span style="color:#FFCB6B;">ERR</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">redis查询失败，尝试查询http， key: </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, key)</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">-- redis查询失败，去查询http</span></span>
<span class="line"><span style="color:#A6ACCD;">            val </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">read_http</span><span style="color:#A6ACCD;">(path, params)</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 查询成功，把数据写入本地缓存</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#FFCB6B;">item_cache</span><span style="color:#A6ACCD;">:</span><span style="color:#82AAFF;">set</span><span style="color:#A6ACCD;">(key, val, expire)</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 返回数据</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> val</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 获取路径参数</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> ngx.</span><span style="color:#FFCB6B;">var</span><span style="color:#A6ACCD;">[</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 查询商品信息</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> itemJSON </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">read_data</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">item:id:</span><span style="color:#89DDFF;">&quot; </span><span style="color:#89DDFF;">..</span><span style="color:#A6ACCD;"> id, </span><span style="color:#F78C6C;">1800</span><span style="color:#A6ACCD;">,  </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">/item/</span><span style="color:#89DDFF;">&quot; </span><span style="color:#89DDFF;">..</span><span style="color:#A6ACCD;"> id, </span><span style="color:#89DDFF;">nil</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 查询库存信息</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> stockJSON </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">read_data</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">item:stock:id:</span><span style="color:#89DDFF;">&quot; </span><span style="color:#89DDFF;">..</span><span style="color:#A6ACCD;"> id, </span><span style="color:#F78C6C;">60</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">/item/stock/</span><span style="color:#89DDFF;">&quot; </span><span style="color:#89DDFF;">..</span><span style="color:#A6ACCD;"> id, </span><span style="color:#89DDFF;">nil</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- JSON转化为lua的table</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> item </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> cjson.</span><span style="color:#82AAFF;">decode</span><span style="color:#A6ACCD;">(itemJSON)</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> stock </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> cjson.</span><span style="color:#82AAFF;">decode</span><span style="color:#A6ACCD;">(stockJSON)</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 组合数据</span></span>
<span class="line"><span style="color:#A6ACCD;">item.</span><span style="color:#FFCB6B;">stock</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> stock.</span><span style="color:#FFCB6B;">stock</span></span>
<span class="line"><span style="color:#A6ACCD;">item.</span><span style="color:#FFCB6B;">sold</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> stock.</span><span style="color:#FFCB6B;">sold</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 把item序列化为json 返回结果</span></span>
<span class="line"><span style="color:#A6ACCD;">ngx.</span><span style="color:#82AAFF;">say</span><span style="color:#A6ACCD;">(cjson.</span><span style="color:#82AAFF;">encode</span><span style="color:#A6ACCD;">(item))</span></span></code></pre></div><h4 id="common-lua" tabindex="-1">common.lua <a class="header-anchor" href="#common-lua" aria-label="Permalink to &quot;common.lua&quot;">​</a></h4><blockquote><p>在<code>/usr/local/openresty/lualib</code>目录下，新建一个common.lua文件：</p></blockquote><div class="language-lua"><button title="Copy Code" class="copy"></button><span class="lang">lua</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 导入redis</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> redis </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">require</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">resty.redis</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 初始化redis</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> red </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">redis</span><span style="color:#A6ACCD;">:</span><span style="color:#82AAFF;">new</span><span style="color:#A6ACCD;">()</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 分别对应建立连接、发送请求、响应结果的超时时间</span></span>
<span class="line"><span style="color:#FFCB6B;">red</span><span style="color:#A6ACCD;">:</span><span style="color:#82AAFF;">set_timeouts</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">1000</span><span style="color:#A6ACCD;">, </span><span style="color:#F78C6C;">1000</span><span style="color:#A6ACCD;">, </span><span style="color:#F78C6C;">1000</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 关闭redis连接的工具方法，其实是放入连接池</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">function</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">close_redis</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;font-style:italic;">red</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> pool_max_idle_time </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">10000</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;">-- 连接的空闲时间，单位是毫秒</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> pool_size </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">100</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;">--连接池大小</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> ok, err </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">red</span><span style="color:#A6ACCD;">:</span><span style="color:#82AAFF;">set_keepalive</span><span style="color:#A6ACCD;">(pool_max_idle_time, pool_size)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">not</span><span style="color:#A6ACCD;"> ok </span><span style="color:#89DDFF;font-style:italic;">then</span></span>
<span class="line"><span style="color:#A6ACCD;">        ngx.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(ngx.</span><span style="color:#FFCB6B;">ERR</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">放入redis连接池失败: </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, err)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 查询redis的方法 ip和port是redis地址，key是查询的key</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">function</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">read_redis</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;font-style:italic;">ip</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">port</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">key</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 获取一个连接</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> ok, err </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">red</span><span style="color:#A6ACCD;">:</span><span style="color:#82AAFF;">connect</span><span style="color:#A6ACCD;">(ip, port)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">not</span><span style="color:#A6ACCD;"> ok </span><span style="color:#89DDFF;font-style:italic;">then</span></span>
<span class="line"><span style="color:#A6ACCD;">        ngx.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(ngx.</span><span style="color:#FFCB6B;">ERR</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">连接redis失败 : </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, err)</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">nil</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 查询redis</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> resp, err </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">red</span><span style="color:#A6ACCD;">:</span><span style="color:#82AAFF;">get</span><span style="color:#A6ACCD;">(key)</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 查询失败处理</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">not</span><span style="color:#A6ACCD;"> resp </span><span style="color:#89DDFF;font-style:italic;">then</span></span>
<span class="line"><span style="color:#A6ACCD;">        ngx.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(ngx.</span><span style="color:#FFCB6B;">ERR</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">查询Redis失败: </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, err, </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">, key = </span><span style="color:#89DDFF;">&quot; </span><span style="color:#A6ACCD;">, key)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">--得到的数据为空处理</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> resp </span><span style="color:#89DDFF;">==</span><span style="color:#A6ACCD;"> ngx.</span><span style="color:#FFCB6B;">null</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">then</span></span>
<span class="line"><span style="color:#A6ACCD;">        resp </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">nil</span></span>
<span class="line"><span style="color:#A6ACCD;">        ngx.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(ngx.</span><span style="color:#FFCB6B;">ERR</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">查询Redis数据为空, key = </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, key)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#82AAFF;">close_redis</span><span style="color:#A6ACCD;">(red)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> resp</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 封装函数，发送http请求，并解析响应</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">function</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">read_http</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;font-style:italic;">path</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">params</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> resp </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> ngx.</span><span style="color:#FFCB6B;">location</span><span style="color:#A6ACCD;">.</span><span style="color:#82AAFF;">capture</span><span style="color:#A6ACCD;">(path,{</span></span>
<span class="line"><span style="color:#A6ACCD;">        method </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> ngx.</span><span style="color:#FFCB6B;">HTTP_GET</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">        args </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> params,</span></span>
<span class="line"><span style="color:#A6ACCD;">    })</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">not</span><span style="color:#A6ACCD;"> resp </span><span style="color:#89DDFF;font-style:italic;">then</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">-- 记录错误信息，返回404</span></span>
<span class="line"><span style="color:#A6ACCD;">        ngx.</span><span style="color:#82AAFF;">log</span><span style="color:#A6ACCD;">(ngx.</span><span style="color:#FFCB6B;">ERR</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">http查询失败, path: </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, path , </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">, args: </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, args)</span></span>
<span class="line"><span style="color:#A6ACCD;">        ngx.</span><span style="color:#82AAFF;">exit</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">404</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> resp.</span><span style="color:#FFCB6B;">body</span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">end</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 将方法导出</span></span>
<span class="line"><span style="color:#89DDFF;">local</span><span style="color:#A6ACCD;"> _M </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> {  </span></span>
<span class="line"><span style="color:#A6ACCD;">    read_http </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> read_http,</span></span>
<span class="line"><span style="color:#A6ACCD;">    read_redis </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> read_redis</span></span>
<span class="line"><span style="color:#A6ACCD;">}  </span></span>
<span class="line"><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> _M</span></span></code></pre></div><h4 id="nginx-conf-1" tabindex="-1">nginx.conf <a class="header-anchor" href="#nginx-conf-1" aria-label="Permalink to &quot;nginx.conf&quot;">​</a></h4><div class="language-nginx"><button title="Copy Code" class="copy"></button><span class="lang">nginx</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">http</span><span style="color:#A6ACCD;"> {</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#89DDFF;"> include </span><span style="color:#A6ACCD;">      mime.types</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#89DDFF;"> default_type </span><span style="color:#A6ACCD;"> application/octet-stream</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#89DDFF;"> sendfile </span><span style="color:#A6ACCD;">      </span><span style="color:#89DDFF;"> on;</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#89DDFF;"> keepalive_timeout </span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">65</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#676E95;font-style:italic;"># 加载lua 模块</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">lua_package_path</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">&quot;/usr/local/openresty/lualib/?.lua;;&quot;</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#676E95;font-style:italic;"># 加载c模块     </span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">lua_package_cpath</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">&quot;/usr/local/openresty/lualib/?.so;;&quot;</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;">  </span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#676E95;font-style:italic;"># 配置nginx缓存，150兆</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">lua_shared_dict</span><span style="color:#A6ACCD;"> item_cache </span><span style="color:#F78C6C;">150m</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;"> </span></span>
<span class="line"><span style="color:#A6ACCD;">     </span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">upstream</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">tomcat-cluster </span><span style="color:#A6ACCD;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">      </span><span style="color:#89DDFF;"> hash $</span><span style="color:#A6ACCD;">request_uri</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">       </span><span style="color:#89DDFF;">server</span><span style="color:#A6ACCD;"> 192.168.0.155:8081;</span></span>
<span class="line"><span style="color:#A6ACCD;">    }</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">server</span><span style="color:#A6ACCD;"> {</span></span>
<span class="line"><span style="color:#A6ACCD;">       </span><span style="color:#89DDFF;"> listen </span><span style="color:#A6ACCD;">      </span><span style="color:#F78C6C;">8081</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">       </span><span style="color:#89DDFF;"> server_name </span><span style="color:#A6ACCD;"> localhost</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">location</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">~</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/api/item/(\d+) </span><span style="color:#A6ACCD;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">       </span><span style="color:#676E95;font-style:italic;"># 默认的响应类型</span></span>
<span class="line"><span style="color:#A6ACCD;">      </span><span style="color:#89DDFF;"> default_type </span><span style="color:#A6ACCD;">application/json</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">       </span><span style="color:#676E95;font-style:italic;"># 响应结果由lua/item.lua文件来决定</span></span>
<span class="line"><span style="color:#A6ACCD;">       </span><span style="color:#89DDFF;">content_by_lua_file</span><span style="color:#A6ACCD;"> lua/item.lua</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">location</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">/item </span><span style="color:#A6ACCD;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">      </span><span style="color:#89DDFF;"> proxy_pass </span><span style="color:#A6ACCD;">http://tomcat-cluster</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    }</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">location</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">/ </span><span style="color:#A6ACCD;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">       </span><span style="color:#89DDFF;"> root </span><span style="color:#A6ACCD;">  html</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">       </span><span style="color:#89DDFF;"> index </span><span style="color:#A6ACCD;"> index.html index.htm</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#89DDFF;"> error_page </span><span style="color:#A6ACCD;">  </span><span style="color:#F78C6C;">500</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">502</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">503</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">504</span><span style="color:#A6ACCD;">  /50x.html</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">location</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/50x.html </span><span style="color:#A6ACCD;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">           </span><span style="color:#89DDFF;"> root </span><span style="color:#A6ACCD;">  html</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">        }</span></span>
<span class="line"><span style="color:#A6ACCD;">    }</span></span>
<span class="line"><span style="color:#A6ACCD;">}</span></span></code></pre></div><div class="language-nginx"><button title="Copy Code" class="copy"></button><span class="lang">nginx</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">nginx</span><span style="color:#A6ACCD;"> -s reload</span></span></code></pre></div><h3 id="访问测试-2" tabindex="-1">访问测试 <a class="header-anchor" href="#访问测试-2" aria-label="Permalink to &quot;访问测试&quot;">​</a></h3><p><a href="http://192.168.22.145:8081/api/item/10001" target="_blank" rel="noreferrer">http://192.168.22.145:8081/api/item/10001</a></p><p>进入<code>/usr/local/openresty/nginx/logs/error.log</code>查看</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209171005096.png" alt="image-20220917100557992" style="zoom:80%;"><h2 id="缓存预热⭐" tabindex="-1">缓存预热⭐ <a class="header-anchor" href="#缓存预热⭐" aria-label="Permalink to &quot;缓存预热⭐&quot;">​</a></h2><blockquote><p>Redis缓存会面临冷启动问题：</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.11/202206091225735.png" alt="image-20220609122535658" style="zoom:80%;"><blockquote><p><strong>冷启动</strong>：服务刚刚启动时，Redis中并没有缓存，如果所有商品数据都在第一次查询时添加缓存，可能会给数据库带来较大压力。</p></blockquote><blockquote><p><strong>缓存预热</strong>：在实际开发中，我们可以利用大数据统计用户访问的热点数据，在项目启动时将这些热点数据提前查询并保存到Redis中。我们数据量较少，并且没有数据统计相关功能，目前可以在启动时将所有数据都放入缓存中。</p></blockquote><blockquote><p>1）启动Redis</p></blockquote><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">redis</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">server </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">etc</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">reids</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">conf</span></span></code></pre></div><blockquote><p>2）在item-service服务中引入Redis依赖</p></blockquote><div class="language-xml"><button title="Copy Code" class="copy"></button><span class="lang">xml</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">org.springframework.boot</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">spring-boot-starter-data-redis</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span></code></pre></div><blockquote><p>3）配置Redis地址</p></blockquote><div class="language-yaml"><button title="Copy Code" class="copy"></button><span class="lang">yaml</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F07178;">spring</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F07178;">redis</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F07178;">host</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">192.168.88.101</span></span></code></pre></div><blockquote><p>4）编写初始化类</p></blockquote><blockquote><p>缓存预热需要在项目启动时完成，并且必须是拿到RedisTemplate之后，这里我们利用InitializingBean接口来实现，因为InitializingBean可以在对象被Spring创建并且成员变量全部注入后执行。</p></blockquote><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Component</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">RedisHandler</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">implements</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">InitializingBean</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Autowired</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">StringRedisTemplate</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Autowired</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">IItemService</span><span style="color:#A6ACCD;"> itemService</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Autowired</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">IItemStockService</span><span style="color:#A6ACCD;"> stockService</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#89DDFF;">	</span><span style="color:#676E95;font-style:italic;">// 进行手动json序列化</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">static</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">final</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">ObjectMapper</span><span style="color:#A6ACCD;"> MAPPER </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">ObjectMapper</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// InitializingBean的默认方法，只要继承，必须实现它</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 该方法会在bean创建完，@Autowired注入成功以后执行，即在项目启动时执行</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Override</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">afterPropertiesSet</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">throws</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Exception</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 初始化缓存</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 1.查询商品信息</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">List</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Item</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> itemList </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> itemService</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">list</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 2.放入缓存</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">for</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">Item</span><span style="color:#A6ACCD;"> item </span><span style="color:#89DDFF;font-style:italic;">:</span><span style="color:#A6ACCD;"> itemList</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">// 2.1.item序列化为JSON</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> json </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> MAPPER</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">writeValueAsString</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">item</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">// 2.2.存入redis</span></span>
<span class="line"><span style="color:#A6ACCD;">            redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForValue</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">set</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">item:id:</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;"> item</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getId</span><span style="color:#89DDFF;">(),</span><span style="color:#A6ACCD;"> json</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 3.查询商品库存信息</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">List</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">ItemStock</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> stockList </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> stockService</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">list</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 4.放入缓存</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">for</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">ItemStock</span><span style="color:#A6ACCD;"> stock </span><span style="color:#89DDFF;font-style:italic;">:</span><span style="color:#A6ACCD;"> stockList</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">// 2.1.item序列化为JSON</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> json </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> MAPPER</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">writeValueAsString</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">stock</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">// 2.2.存入redis</span></span>
<span class="line"><span style="color:#A6ACCD;">            redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForValue</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">set</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">item:stock:id:</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;"> stock</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getId</span><span style="color:#89DDFF;">(),</span><span style="color:#A6ACCD;"> json</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209161955422.png" alt="image-20220916195548298" style="zoom:80%;"><h2 id="多级缓存同步⭐" tabindex="-1">多级缓存同步⭐ <a class="header-anchor" href="#多级缓存同步⭐" aria-label="Permalink to &quot;多级缓存同步⭐&quot;">​</a></h2><blockquote><p>大多数情况下，浏览器查询到的都是缓存数据，如果缓存数据与数据库数据存在较大差异，可能会产生比较严重的后果。所以我们必须保证数据库数据、缓存数据的一致性，这就是缓存与数据库的同步。</p></blockquote><h3 id="数据同步策略" tabindex="-1">数据同步策略 <a class="header-anchor" href="#数据同步策略" aria-label="Permalink to &quot;数据同步策略&quot;">​</a></h3><blockquote><p>缓存数据同步的常见方式有三种：</p></blockquote><h4 id="设置有效期" tabindex="-1">设置有效期 <a class="header-anchor" href="#设置有效期" aria-label="Permalink to &quot;设置有效期&quot;">​</a></h4><blockquote><p>给缓存设置有效期，到期后自动删除。再次查询时更新</p></blockquote><blockquote><ul><li>优势：简单、方便</li><li>缺点：时效性差，缓存过期之前可能不一致</li><li>场景：更新频率较低，时效性要求低的业务</li></ul></blockquote><h4 id="同步双写" tabindex="-1">同步双写 <a class="header-anchor" href="#同步双写" aria-label="Permalink to &quot;同步双写&quot;">​</a></h4><blockquote><p>在修改数据库的同时，直接修改缓存</p></blockquote><blockquote><ul><li>优势：时效性强，缓存与数据库强一致</li><li>缺点：有代码侵入，耦合度高；</li><li>场景：对一致性、时效性要求较高的缓存数据</li></ul></blockquote><h4 id="异步通知" tabindex="-1">异步通知 <a class="header-anchor" href="#异步通知" aria-label="Permalink to &quot;异步通知&quot;">​</a></h4><blockquote><p>修改数据库时发送事件通知，相关服务监听到通知后修改缓存数据，可以基于MQ或者Canal来实现</p></blockquote><blockquote><ul><li>优势：低耦合，可以同时通知多个缓存服务</li><li>缺点：时效性一般，可能存在中间不一致状态</li><li>场景：时效性要求一般，有多个服务需要同步</li></ul></blockquote><h5 id="_1-基于mq的异步通知" tabindex="-1">1）基于MQ的异步通知 <a class="header-anchor" href="#_1-基于mq的异步通知" aria-label="Permalink to &quot;1）基于MQ的异步通知&quot;">​</a></h5><blockquote><ul><li>商品服务完成对数据的修改后，只需要发送一条消息到MQ中。</li><li>缓存服务监听MQ消息，然后完成对缓存的更新，依然有少量的代码侵入</li></ul></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20210821115552327.png" alt="image-20210821115552327" style="zoom:50%;"><h5 id="_2-基于canal的通知" tabindex="-1">2）基于Canal的通知 <a class="header-anchor" href="#_2-基于canal的通知" aria-label="Permalink to &quot;2）基于Canal的通知&quot;">​</a></h5><blockquote><ul><li>商品服务完成商品修改后，业务直接结束，没有任何代码侵入</li><li>Canal监听MySQL变化，当发现变化后，立即通知缓存服务</li><li>缓存服务接收到canal通知，更新缓存</li></ul></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20210821115719363.png" alt="image-20210821115719363" style="zoom:50%;"><h3 id="canal概述" tabindex="-1">Canal概述 <a class="header-anchor" href="#canal概述" aria-label="Permalink to &quot;Canal概述&quot;">​</a></h3><blockquote><p><strong>Canal [kə&#39;næl]</strong>，译意为水道/管道/沟渠，canal是阿里巴巴旗下的一款开源项目，基于Java开发。基于数据库增量日志解析，提供增量数据订阅&amp;消费。GitHub的地址：<a href="https://github.com/alibaba/canal" target="_blank" rel="noreferrer">https://github.com/alibaba/canal</a></p></blockquote><blockquote><p>Canal是基于mysql的主从同步来实现的，MySQL主从同步的原理如下：</p></blockquote><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20210821115914748.png" alt="image-20210821115914748"></p><blockquote><p>1）MySQL master 将数据变更写入二进制日志( binary log），其中记录的数据叫做binary log events</p><p>2）MySQL slave 将 master 的 binary log events拷贝到它的中继日志(relay log)</p><p>3）MySQL slave 重放 relay log 中事件，将数据变更反映它自己的数据</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20210821120049024.png" alt="image-20210821120049024" style="zoom:80%;"><blockquote><p>Canal就是把自己伪装成MySQL的一个slave节点，从而监听master的binary log变化。再把得到的变化信息通知给Canal的客户端，进而完成对其它数据库的同步。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20210821115948395.png" alt="image-20210821115948395" style="zoom:80%;"><h3 id="mysql配置" tabindex="-1">MySQL配置 <a class="header-anchor" href="#mysql配置" aria-label="Permalink to &quot;MySQL配置&quot;">​</a></h3><blockquote><p>注意：这里只需要开启主库的配置，不用去管从库，因为从库是canal伪装的</p></blockquote><h4 id="修改配置文件" tabindex="-1">修改配置文件 <a class="header-anchor" href="#修改配置文件" aria-label="Permalink to &quot;修改配置文件&quot;">​</a></h4><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 查看MySQL配置文件位置</span></span>
<span class="line"><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">usr</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">bin</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">mysql </span><span style="color:#89DDFF;">--</span><span style="color:#A6ACCD;">verbose </span><span style="color:#89DDFF;">--</span><span style="color:#A6ACCD;">help </span><span style="color:#89DDFF;">|</span><span style="color:#A6ACCD;"> grep </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">A </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">Default options</span><span style="color:#89DDFF;">&#39;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5.13/202205261501433.png" alt="image-20220526150106366" style="zoom:80%;"><blockquote><p>这个信息的意思是： 服务器首先读取的是/etc/my.cnf文件，如果前一个文件不存在则继续读/etc/mysql/my.cnf文件，如若还不存在便会去读~/.my.cnf文件</p></blockquote><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#FFCB6B;">vim</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/etc/my.cnf</span></span></code></pre></div><blockquote><p>文件的内容如下：除了server_id，其他内容可选</p></blockquote><div class="language-ini"><button title="Copy Code" class="copy"></button><span class="lang">ini</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">[mysqld]</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">## 设置server_id，同一局域网中需要唯一</span></span>
<span class="line"><span style="color:#F07178;">server_id</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">101</span></span>
<span class="line"><span style="color:#A6ACCD;">skip-name-resolve</span></span>
<span class="line"><span style="color:#F07178;">character_set_server</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">utf8</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 只需要对这个数据库进行主从</span></span>
<span class="line"><span style="color:#F07178;">binlog-do-db</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">xue</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">## 指定不需要同步的数据库名称</span></span>
<span class="line"><span style="color:#F07178;">binlog-ignore-db</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">mysql</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">## 开启二进制日志功能</span></span>
<span class="line"><span style="color:#F07178;">log-bin</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">mysql-bin</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">## 设置二进制日志使用内存大小（事务）</span></span>
<span class="line"><span style="color:#F07178;">binlog_cache_size</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">1M</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">## 设置使用的二进制日志格式（mixed,statement,row）</span></span>
<span class="line"><span style="color:#F07178;">binlog_format</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">row</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">## 二进制日志过期清理时间。默认值为0，表示不自动清理。</span></span>
<span class="line"><span style="color:#F07178;">expire_logs_days</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">7</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">## 跳过主从复制中遇到的所有错误或指定类型的错误，避免slave端复制中断。</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">## 如：1062错误是指一些主键重复，1032错误是因为主从数据库数据不一致</span></span>
<span class="line"><span style="color:#F07178;">slave_skip_errors</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">1062</span></span></code></pre></div><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 配置完成后需要重新启动MySQL</span></span>
<span class="line"><span style="color:#A6ACCD;">systemctl restart mysqld</span></span></code></pre></div><h4 id="测试使用" tabindex="-1">测试使用 <a class="header-anchor" href="#测试使用" aria-label="Permalink to &quot;测试使用&quot;">​</a></h4><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">mysql </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456</span></span></code></pre></div><p>重启成功后通过如下命令查看binlog是否启用</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">show variables like </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">%log_bin%</span><span style="color:#89DDFF;">&#39;</span><span style="color:#89DDFF;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209162313645.png" alt="image-20220916231324523" style="zoom:80%;"><p>再查看下MySQL的binlog模式；</p><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">show variables like &#39;binlog_format%&#39;;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5.13/202205251457036.png" alt="image-20220525145755987" style="zoom:80%;"><p>查看binlog位置</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">show master status</span><span style="color:#89DDFF;">;</span></span></code></pre></div> <img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209162240919.png" alt="image-20220916224058676" style="zoom:80%;"><h4 id="创建canal用户" tabindex="-1">创建canal用户 <a class="header-anchor" href="#创建canal用户" aria-label="Permalink to &quot;创建canal用户&quot;">​</a></h4><p>接下来添加一个仅用于数据同步的账户，出于安全考虑，这里仅提供对heima这个库的操作权限。</p><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 降低密码等级</span></span>
<span class="line"><span style="color:#A6ACCD;">set global validate_password.policy=0;</span></span>
<span class="line"><span style="color:#A6ACCD;">set global validate_password.length=4;</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 创建用户授予权限</span></span>
<span class="line"><span style="color:#A6ACCD;">create user &#39;canal&#39;@&#39;%&#39; identified by &#39;canal&#39;;</span></span>
<span class="line"><span style="color:#A6ACCD;">GRANT SELECT ,REPLICATION SLAVE , REPLICATION CLIENT,super ON *.* TO &#39;canal&#39;@&#39;%&#39;;</span></span>
<span class="line"><span style="color:#A6ACCD;">use mysql;</span></span>
<span class="line"><span style="color:#A6ACCD;">alter user &#39;canal&#39;@&#39;%&#39; identified with mysql_native_password by &#39;canal&#39;;</span></span>
<span class="line"><span style="color:#A6ACCD;">FLUSH PRIVILEGES;</span></span></code></pre></div><h3 id="canal搭建" tabindex="-1">Canal搭建 <a class="header-anchor" href="#canal搭建" aria-label="Permalink to &quot;Canal搭建&quot;">​</a></h3><h4 id="docker版安装⭐" tabindex="-1">Docker版安装⭐ <a class="header-anchor" href="#docker版安装⭐" aria-label="Permalink to &quot;Docker版安装⭐&quot;">​</a></h4><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;"># 创建网络，方便后续Docker版的mq等连进来</span></span>
<span class="line"><span style="color:#FFCB6B;">docker</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">network</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">heima</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 因为我没用docker版的mysql和springboot，因此此步骤可以省略</span></span>
<span class="line"><span style="color:#FFCB6B;">docker</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">network</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">connect</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">heima</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">mysql</span></span></code></pre></div><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#FFCB6B;">docker</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">run</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-p</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">11111</span><span style="color:#C3E88D;">:11111</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">--name</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">canal</span><span style="color:#A6ACCD;"> \</span></span>
<span class="line"><span style="color:#A6ACCD;">-e </span><span style="color:#C3E88D;">canal.destinations=heima</span><span style="color:#A6ACCD;"> \</span></span>
<span class="line"><span style="color:#A6ACCD;">-e </span><span style="color:#C3E88D;">canal.instance.master.address=</span><span style="color:#F78C6C;">192.168</span><span style="color:#C3E88D;">.88.101:3306</span><span style="color:#A6ACCD;">  \</span></span>
<span class="line"><span style="color:#A6ACCD;">-e </span><span style="color:#C3E88D;">canal.instance.dbUsername=canal</span><span style="color:#A6ACCD;">  \</span></span>
<span class="line"><span style="color:#A6ACCD;">-e </span><span style="color:#C3E88D;">canal.instance.dbPassword=canal</span><span style="color:#A6ACCD;">  \</span></span>
<span class="line"><span style="color:#A6ACCD;">-e </span><span style="color:#C3E88D;">canal.instance.connectionCharset=UTF-8</span><span style="color:#A6ACCD;"> \</span></span>
<span class="line"><span style="color:#A6ACCD;">-e </span><span style="color:#C3E88D;">canal.instance.tsdb.enable=</span><span style="color:#89DDFF;">true</span><span style="color:#A6ACCD;"> \</span></span>
<span class="line"><span style="color:#A6ACCD;">-e </span><span style="color:#C3E88D;">canal.instance.gtidon=</span><span style="color:#89DDFF;">false</span><span style="color:#A6ACCD;">  \</span></span>
<span class="line"><span style="color:#A6ACCD;">-e </span><span style="color:#C3E88D;">canal.instance.filter.regex=.</span><span style="color:#A6ACCD;">*</span><span style="color:#A6ACCD;">\\</span><span style="color:#C3E88D;">..</span><span style="color:#A6ACCD;">*</span><span style="color:#A6ACCD;"> \</span></span>
<span class="line"><span style="color:#A6ACCD;">--network </span><span style="color:#C3E88D;">heima</span><span style="color:#A6ACCD;"> \</span></span>
<span class="line"><span style="color:#A6ACCD;">-d </span><span style="color:#C3E88D;">canal/canal-server:v1.1.5</span></span></code></pre></div><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#FFCB6B;">docker</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">exec</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-it</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">canal</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">bash</span></span>
<span class="line"><span style="color:#FFCB6B;">tail</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-f</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">canal-server/logs/canal/canal.log</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 这个才是看真实是否连接成功的</span></span>
<span class="line"><span style="color:#FFCB6B;">tail</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-f</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">canal-server/logs/heima/heima.log</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202306130936919.png" alt="image-20230613093619660" style="zoom:80%;"><ul><li><code>-p 11111:11111</code>：这是canal的默认监听端口</li><li><code>-e canal.instance.master.address=mysql:3306</code>：数据库地址和端口，如果不知道mysql容器地址，可以通过<code>docker inspect 容器id</code>来查看</li><li>canal.destinations=heima:canal集群名称</li><li><code>-e canal.instance.dbUsername=canal</code>：数据库用户名</li><li><code>-e canal.instance.dbPassword=canal</code> ：数据库密码</li><li><code>-e canal.instance.filter.regex=</code>：要监听的表名称</li></ul><p>表名称监听支持的语法：</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">mysql 数据解析关注的表，Perl正则表达式.</span></span>
<span class="line"><span style="color:#A6ACCD;">多个正则之间以逗号(,)分隔，转义符需要双斜杠(\\) </span></span>
<span class="line"><span style="color:#A6ACCD;">常见例子：</span></span>
<span class="line"><span style="color:#A6ACCD;">1.  所有表：.*   or  .*\\..*</span></span>
<span class="line"><span style="color:#A6ACCD;">2.  canal schema下所有表： canal\\..*</span></span>
<span class="line"><span style="color:#A6ACCD;">3.  canal下的以canal打头的表：canal\\.canal.*</span></span>
<span class="line"><span style="color:#A6ACCD;">4.  canal schema下的一张表：canal.test1</span></span>
<span class="line"><span style="color:#A6ACCD;">5.  多个规则组合使用然后以逗号隔开：canal\\..*,mysql.test1,mysql.test2</span></span></code></pre></div><h4 id="压缩包版安装" tabindex="-1">压缩包版安装 <a class="header-anchor" href="#压缩包版安装" aria-label="Permalink to &quot;压缩包版安装&quot;">​</a></h4><p>安装好JDK，将我们下载好的压缩包<code>canal.deployer-1.1.5-SNAPSHOT.tar.gz</code>上传到Linux服务器</p><p>进入下载地址：<a href="https://github.com/alibaba/canal/releases/download" target="_blank" rel="noreferrer">https://github.com/alibaba/canal/releases/download</a></p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209170907649.png" alt="image-20220917090710582" style="zoom:80%;"><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">mkdir </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">root</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">canal</span></span>
<span class="line"><span style="color:#A6ACCD;">tar </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">xvf canal</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">deployer</span><span style="color:#89DDFF;">-</span><span style="color:#F78C6C;">1.1.6</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">tar</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">gz </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">C </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">root</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">canal</span></span></code></pre></div><p>目录结构</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">tree canal</span></span></code></pre></div><div class="language-c"><button title="Copy Code" class="copy"></button><span class="lang">c</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">├── bin</span></span>
<span class="line"><span style="color:#A6ACCD;">│   ├── restart.sh</span></span>
<span class="line"><span style="color:#A6ACCD;">│   ├── startup.bat</span></span>
<span class="line"><span style="color:#A6ACCD;">│   ├── startup.sh</span></span>
<span class="line"><span style="color:#A6ACCD;">│   └── stop.sh</span></span>
<span class="line"><span style="color:#A6ACCD;">├── conf</span></span>
<span class="line"><span style="color:#A6ACCD;">│   ├── canal_local.properties</span></span>
<span class="line"><span style="color:#A6ACCD;">│   ├── canal.properties</span></span>
<span class="line"><span style="color:#A6ACCD;">│   └── example</span></span>
<span class="line"><span style="color:#A6ACCD;">│       └── instance.properties</span></span>
<span class="line"><span style="color:#A6ACCD;">├── lib</span></span>
<span class="line"><span style="color:#A6ACCD;">├── logs</span></span>
<span class="line"><span style="color:#A6ACCD;">│   ├── canal</span></span>
<span class="line"><span style="color:#A6ACCD;">│   │   └── canal.log</span></span>
<span class="line"><span style="color:#A6ACCD;">│   └── example</span></span>
<span class="line"><span style="color:#A6ACCD;">│       ├── example.log</span></span>
<span class="line"><span style="color:#A6ACCD;">│       └── example.log</span></span>
<span class="line"><span style="color:#A6ACCD;">└── plugin</span></span></code></pre></div><p>配置文件(基本不改)</p><blockquote><p>目录：conf/example/instance.properties</p></blockquote><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">cd </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">root</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">canal</span></span>
<span class="line"><span style="color:#A6ACCD;">vi conf</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">example</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">instance</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">properties</span></span></code></pre></div><p>主要编辑内容如下</p><p>注意解开注释，其余就空着就行了</p><div class="language-properties"><button title="Copy Code" class="copy"></button><span class="lang">properties</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;"># 需要同步数据的MySQL地址</span></span>
<span class="line"><span style="color:#F07178;">canal.instance.master.address</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">127.0.0.1:3306</span></span>
<span class="line"><span style="color:#F07178;">canal.instance.master.journal.name</span><span style="color:#89DDFF;">=</span></span>
<span class="line"><span style="color:#F07178;">canal.instance.master.position</span><span style="color:#89DDFF;">=</span></span>
<span class="line"><span style="color:#F07178;">canal.instance.master.timestamp</span><span style="color:#89DDFF;">=</span></span>
<span class="line"><span style="color:#F07178;">canal.instance.master.gtid</span><span style="color:#89DDFF;">=</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 用于同步数据的数据库账号</span></span>
<span class="line"><span style="color:#F07178;">canal.instance.dbUsername</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">canal</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 用于同步数据的数据库密码</span></span>
<span class="line"><span style="color:#F07178;">canal.instance.dbPassword</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">canal</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 数据库连接编码</span></span>
<span class="line"><span style="color:#F07178;">canal.instance.connectionCharset</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> UTF-8</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 需要订阅binlog的表过滤正则表达式</span></span>
<span class="line"><span style="color:#F07178;">canal.instance.filter.regex</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">.*\\..*</span></span></code></pre></div><blockquote><p>目录：/root/canal/conf/canal.properties</p></blockquote><div class="language-properties"><button title="Copy Code" class="copy"></button><span class="lang">properties</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;"># 可以配置下</span></span>
<span class="line"><span style="color:#F07178;">canal.destinations</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> example</span></span></code></pre></div><blockquote><p>启动关闭重启,注意要在canal主目录下</p></blockquote><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;">启动服务</span></span>
<span class="line"><span style="color:#A6ACCD;">sh bin</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">startup</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">sh</span></span></code></pre></div><p>启动成功后可使用如下命令查看服务日志信息；</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">tail </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">f logs</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">canal</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">canal</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">log</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220402111322230.png" alt="image-20220402111322230" style="zoom:67%;"><p>启动成功后可使用如下命令查看instance日志信息；</p><div class="language-c"><button title="Copy Code" class="copy"></button><span class="lang">c</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">tail </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">f logs</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">example</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">example.log</span></span></code></pre></div><p>如果想要停止<code>canal-server</code>服务可以使用如下命令。</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">sh bin</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">stop</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">sh</span></span></code></pre></div><p>重启</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">sh bin</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">restart</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">sh</span></span></code></pre></div><p>查看canal的监听端口</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">netstat </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">tulpn</span></span></code></pre></div><ul><li>11110：canal admin端口</li><li>11111：canal监听端口</li><li>11112：指标监控端口</li></ul><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220402113657614.png" alt="image-20220402113657614" style="zoom:67%;"><h3 id="基础使用⭐" tabindex="-1">基础使用⭐ <a class="header-anchor" href="#基础使用⭐" aria-label="Permalink to &quot;基础使用⭐&quot;">​</a></h3><blockquote><p>我们可以利用Canal提供的Java客户端，监听Canal通知消息。当收到变化的消息时，完成对缓存的更新。不过这里我们会使用GitHub上的第三方开源的canal-starter客户端，与SpringBoot完美整合，自动装配，比官方客户端要简单好用很多。</p></blockquote><blockquote><p>地址：<a href="https://github.com/NormanGyllenhaal/canal-client" target="_blank" rel="noreferrer">https://github.com/NormanGyllenhaal/canal-client</a></p></blockquote><blockquote><p>引入依赖，编写配置</p></blockquote><div class="language-xml"><button title="Copy Code" class="copy"></button><span class="lang">xml</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">top.javatool</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">canal-spring-boot-starter</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">version</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">1.2.1-RELEASE</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">version</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span></code></pre></div><div class="language-yaml"><button title="Copy Code" class="copy"></button><span class="lang">yaml</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F07178;">canal</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F07178;">destination</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">heima</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;"># canal的集群名字，要与安装canal时设置的名称一致</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F07178;">server</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">192.168.88.101:11111</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;"># canal服务地址</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 注意数据库连接也要改成上面Mysql配置的数据库</span></span>
<span class="line"><span style="color:#F07178;">spring</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F07178;">application</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F07178;">name</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">itemservice</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F07178;">datasource</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F07178;">url</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">jdbc:mysql://192.168.88.101:3306/xue?useSSL=false</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209170929295.png" alt="image-20220917092909161" style="zoom:80%;"><h4 id="监听单表" tabindex="-1">监听单表 <a class="header-anchor" href="#监听单表" aria-label="Permalink to &quot;监听单表&quot;">​</a></h4><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Data</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">TableName</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">tb_item</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">Item</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">TableId</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">type</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> IdType</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">AUTO</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> id</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//商品id</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> name</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//商品名称</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> title</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//商品标题</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> price</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//价格（分）</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> image</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//商品图片</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> category</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//分类名称</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> brand</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//品牌名称</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> spec</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//规格</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Integer</span><span style="color:#A6ACCD;"> status</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//商品状态 1-正常，2-下架</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Date</span><span style="color:#A6ACCD;"> createTime</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//创建时间</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Date</span><span style="color:#A6ACCD;"> updateTime</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//更新时间</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">TableField</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">exist</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">false)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Integer</span><span style="color:#A6ACCD;"> stock</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">TableField</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">exist</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">false)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Integer</span><span style="color:#A6ACCD;"> sold</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">CanalTable</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">value</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">tb_item</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Component</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Slf4j</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">ItemHandler</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">implements</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">EntryHandler</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Item</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 新增操作</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Override</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">insert</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">Item</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">item</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">//你的逻辑</span></span>
<span class="line"><span style="color:#A6ACCD;">        log</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">info</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">新增 {}</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">item</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 对于更新操作来讲，before中的属性只包含变更的属性</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// after 包含所有属性，通过对比可发现那些属性更新了</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Override</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">update</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">Item</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">before</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Item</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">after</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">//你的逻辑</span></span>
<span class="line"><span style="color:#A6ACCD;">        log</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">info</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">更新 {} {}</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">before</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">after</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 删除操作</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Override</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">delete</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">Item</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">item</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">//你的逻辑</span></span>
<span class="line"><span style="color:#A6ACCD;">        log</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">info</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">删除 {}</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">item</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h4 id="监听所有表" tabindex="-1">监听所有表 <a class="header-anchor" href="#监听所有表" aria-label="Permalink to &quot;监听所有表&quot;">​</a></h4><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">CanalTable</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">value</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">all</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Component</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Slf4j</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">authorHandler</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">implements</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">EntryHandler</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Map</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">&gt;&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Override</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">insert</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">Map</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">map</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        log</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">info</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">insert message  {}</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> map</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Override</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">update</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">Map</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">before</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Map</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">after</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        log</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">info</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">update before {} </span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> before</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        log</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">info</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">update after {}</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> after</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Override</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">delete</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">Map</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">map</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        log</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">info</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">delete  {}</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> map</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209170940504.png" alt="image-20220917094044400" style="zoom:80%;"><h3 id="实战应用" tabindex="-1">实战应用 <a class="header-anchor" href="#实战应用" aria-label="Permalink to &quot;实战应用&quot;">​</a></h3><h4 id="修改item实体类" tabindex="-1">修改Item实体类 <a class="header-anchor" href="#修改item实体类" aria-label="Permalink to &quot;修改Item实体类&quot;">​</a></h4><blockquote><p>Canal推送给canal-client的是被修改的这一行数据（row），而我们引入的canal-client则会帮我们把行数据封装到Item实体类中。这个过程中需要知道数据库与实体的映射关系，要用到JPA的几个注解：</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205032232860.png" alt="image-20220503223236748" style="zoom:80%;"><blockquote><p>通过@Id、@Column、等注解完成Item与数据库表字段的映射：</p></blockquote><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Data</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">TableName</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">tb_item</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">Item</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">TableId</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">type</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> IdType</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">AUTO</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Id</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> id</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//商品id</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Column</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">name</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">name</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> name</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//商品名称</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> title</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//商品标题</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> price</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//价格（分）</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> image</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//商品图片</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> category</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//分类名称</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> brand</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//品牌名称</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> spec</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//规格</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Integer</span><span style="color:#A6ACCD;"> status</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//商品状态 1-正常，2-下架</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Date</span><span style="color:#A6ACCD;"> createTime</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//创建时间</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Date</span><span style="color:#A6ACCD;"> updateTime</span><span style="color:#89DDFF;">;</span><span style="color:#676E95;font-style:italic;">//更新时间</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">TableField</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">exist</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">false)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Transient</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Integer</span><span style="color:#A6ACCD;"> stock</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">TableField</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">exist</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">false)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Transient</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Integer</span><span style="color:#A6ACCD;"> sold</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h4 id="编写监听器-重点" tabindex="-1">编写监听器(重点) <a class="header-anchor" href="#编写监听器-重点" aria-label="Permalink to &quot;编写监听器(重点)&quot;">​</a></h4><blockquote><p>通过实现<code>EntryHandler&lt;T&gt;</code>接口编写监听器，监听Canal消息。注意两点：</p></blockquote><ul><li>实现类通过<code>@CanalTable(&quot;tb_item&quot;)</code>指定监听的表信息</li><li>EntryHandler的泛型是与表对应的实体类</li></ul><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205032233573.png" alt="image-20220503223320453" style="zoom:80%;"><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">CanalTable</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">tb_item</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Component</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">ItemHandler</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">implements</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">EntryHandler</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Item</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">	</span><span style="color:#676E95;font-style:italic;">// 缓存预热</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Autowired</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">RedisHandler</span><span style="color:#A6ACCD;"> redisHandler</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// JVM缓存</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Autowired</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Cache</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Long</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Item</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> itemCache</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Override</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">insert</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">Item</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">item</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 写数据到JVM进程缓存</span></span>
<span class="line"><span style="color:#A6ACCD;">        itemCache</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">put</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">item</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getId</span><span style="color:#89DDFF;">(),</span><span style="color:#A6ACCD;"> item</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 写数据到redis</span></span>
<span class="line"><span style="color:#A6ACCD;">        redisHandler</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">saveItem</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">item</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Override</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">update</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">Item</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">before</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Item</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">after</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 写数据到JVM进程缓存</span></span>
<span class="line"><span style="color:#A6ACCD;">        itemCache</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">put</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">after</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getId</span><span style="color:#89DDFF;">(),</span><span style="color:#A6ACCD;"> after</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 写数据到redis</span></span>
<span class="line"><span style="color:#A6ACCD;">        redisHandler</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">saveItem</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">after</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Override</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">delete</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">Item</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">item</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 删除数据到JVM进程缓存</span></span>
<span class="line"><span style="color:#A6ACCD;">        itemCache</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">invalidate</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">item</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getId</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 删除数据到redis</span></span>
<span class="line"><span style="color:#A6ACCD;">        redisHandler</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">deleteItemById</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">item</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getId</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><blockquote><p>RedisHandler是我们之前做缓存预热时编写的一个类，新增内容如下：</p></blockquote><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Component</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">RedisHandler</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">implements</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">InitializingBean</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Autowired</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">StringRedisTemplate</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">....</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">saveItem</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">Item</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">item</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">try</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> json </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> MAPPER</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">writeValueAsString</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">item</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">            redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForValue</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">set</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">item:id:</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;"> item</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getId</span><span style="color:#89DDFF;">(),</span><span style="color:#A6ACCD;"> json</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">catch</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">JsonProcessingException</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">e</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;font-style:italic;">throw</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">RuntimeException</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">e</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">deleteItemById</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">id</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">delete</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">item:id:</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;"> id</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><blockquote><p>修改数据库tb_item表，查看Redis和JVM缓存中数据是否发送修改，结果已经成功修改</p></blockquote><h1 id="内存策略⭐" tabindex="-1">内存策略⭐ <a class="header-anchor" href="#内存策略⭐" aria-label="Permalink to &quot;内存策略⭐&quot;">​</a></h1><p>Redis之所以性能强，最主要的原因就是基于内存存储。然而单节点的Redis其内存大小不宜过大，会影响持久化或主从同步性能。我们可以通过修改配置文件来设置Redis的最大内存：</p><h2 id="设置内存大小和淘汰策略⭐" tabindex="-1">设置内存大小和淘汰策略⭐ <a class="header-anchor" href="#设置内存大小和淘汰策略⭐" aria-label="Permalink to &quot;设置内存大小和淘汰策略⭐&quot;">​</a></h2><h3 id="设置最大内存" tabindex="-1">设置最大内存 <a class="header-anchor" href="#设置最大内存" aria-label="Permalink to &quot;设置最大内存&quot;">​</a></h3><p>首先 <code>Redis</code> 提供了一个参数 <code>maxmemory</code> 来配置 <code>Redis</code> 最大使用内存：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209181326831.png" alt="image-20220918132618756" style="zoom:80%;"><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">maxmemory </span><span style="color:#89DDFF;">&lt;</span><span style="color:#A6ACCD;">bytes</span><span style="color:#89DDFF;">&gt;</span></span></code></pre></div><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 获取Redis能使用的最大内存大小</span></span>
<span class="line"><span style="color:#A6ACCD;">config get maxmemory</span></span>
<span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;">设置Redis最大占用内存大小为</span><span style="color:#F78C6C;">100M</span></span>
<span class="line"><span style="color:#A6ACCD;">config set maxmemory </span><span style="color:#F78C6C;">100mb</span></span></code></pre></div><p>或者也可以通过命令 <code>config set maxmemory 1GB</code> 来动态修改。如果没有设置该参数，那么在 <code>32</code> 位的操作系统中 <code>Redis</code> 最多使用 <code>3GB</code> 内存，而在 <code>64</code> 位的操作系统中则不限制</p><h3 id="设置和获取内存淘汰策略" tabindex="-1">设置和获取内存淘汰策略 <a class="header-anchor" href="#设置和获取内存淘汰策略" aria-label="Permalink to &quot;设置和获取内存淘汰策略&quot;">​</a></h3><blockquote><p>PS：淘汰策略也可以直接使用命令 <code>config set maxmemory-policy &lt;策略&gt;</code> 来进行动态配置。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209181445045.png" alt="image-20220918144505969" style="zoom:80%;"><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 配置文件修改策略</span></span>
<span class="line"><span style="color:#A6ACCD;">maxmemory</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">policy allkeys</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">lru</span></span></code></pre></div><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 通过配置文件设置淘汰策略（修改redis</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">conf文件）</span></span>
<span class="line"><span style="color:#A6ACCD;">config get maxmemory</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">policy</span></span>
<span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 通过命令修改淘汰策略</span></span>
<span class="line"><span style="color:#A6ACCD;">config set maxmemory</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">policy allkeys</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">lru</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208092318829.png" alt="image-20220809231835690" style="zoom:67%;"><p>可以看到当前使用的默认的noeviction策略</p><h2 id="内存过期策略" tabindex="-1">内存过期策略 <a class="header-anchor" href="#内存过期策略" aria-label="Permalink to &quot;内存过期策略&quot;">​</a></h2><p>当内存使用达到上限时，就无法存储更多数据了。为了解决这个问题，Redis提供了一些策略实现内存回收：</p><ul><li>内存过期策略</li><li>内存淘汰策略</li></ul><h3 id="内存过期设置" tabindex="-1">内存过期设置 <a class="header-anchor" href="#内存过期设置" aria-label="Permalink to &quot;内存过期设置&quot;">​</a></h3><p>在学习Redis缓存的时候我们说过，可以通过expire命令给Redis的key设置TTL（存活时间）：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209181327796.png" alt="image-20220918132741711" style="zoom:80%;"><blockquote><p>可以发现，当key的TTL到期以后，再次访问name返回的是nil，说明这个key已经不存在了，对应的内存也得到释放。从而起到内存回收的目的。</p></blockquote><h3 id="过期策略-db结构" tabindex="-1">过期策略-DB结构 <a class="header-anchor" href="#过期策略-db结构" aria-label="Permalink to &quot;过期策略-DB结构&quot;">​</a></h3><blockquote><p>Redis本身是一个典型的key-value内存存储数据库，因此所有的key、value都保存在之前学习过的Dict结构中。不过在其database结构体中，有两个Dict：一个用来记录key-value；另一个用来记录key-TTL。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209181428375.png" alt="image-20220918142839279" style="zoom:80%;"><h3 id="过期删除策略⭐" tabindex="-1">过期删除策略⭐ <a class="header-anchor" href="#过期删除策略⭐" aria-label="Permalink to &quot;过期删除策略⭐&quot;">​</a></h3><p>如果将一个过期的键删除，我们一般都会有三种策略：</p><h4 id="惰性删除" tabindex="-1">惰性删除 <a class="header-anchor" href="#惰性删除" aria-label="Permalink to &quot;惰性删除&quot;">​</a></h4><blockquote><p>不管键有没有过期都不主动删除，等到每次去获取键时再判断是否过期，如果过期就删除该键，否则返回键对应的值。这种策略对内存不够友好，可能会浪费很多内存。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209181434462.png" alt="image-20220918143428362" style="zoom:80%;"><p>在 <code>Redis</code> 当中，其选择的是策略 <code>2</code> 和策略 <code>3</code> 的综合使用。不过 <code>Redis</code> 的定期扫描只会扫描设置了过期时间的键，因为设置了过期时间的键 <code>Redis</code> 会单独存储，所以不会出现扫描所有键的情况：</p><h4 id="周期删除" tabindex="-1">周期删除 <a class="header-anchor" href="#周期删除" aria-label="Permalink to &quot;周期删除&quot;">​</a></h4><blockquote><p>为每个键设置一个定时器，一旦过期时间到了，周期性的<strong>抽样部分过期的key</strong>，则将键删除。这种策略对内存很友好，但是对 <code>CPU</code> 不友好，因为每个定时器都会占用一定的 <code>CPU</code> 资源。</p></blockquote><ul><li>Redis服务初始化函数<code>initServer()</code>中设置定时任务，按照server.hz的频率来执行过期key清理，<code>模式为SLOW</code></li><li>Redis的每个事件循环前会调用<code>beforeSleep()</code>函数，执行过期key清理，<code>模式为FAST</code></li></ul><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209181437400.png" alt="image-20220918143702301" style="zoom:80%;"><p><strong>SLOW</strong>模式规则：</p><p>①执行频率受server.hz影响，默认为10，即每秒执行10次，每个执行周期100ms。</p><p>②<code>执行清理耗时不超过一次执行周期的25%，执行频率默认为10，默认slow模式耗时不超过25ms</code></p><p>③逐个遍历db，逐个遍历db中的bucket，抽取20个key判断是否过期</p><p>④如果没达到时间上限（25ms）并且过期key比例大于10%，再进行一次抽样，否则结束</p><p><strong>FAST</strong>模式规则（过期key比例小于10%不执行 ）：</p><p>①执行频率受beforeSleep()调用频率影响，<code>但两次FAST模式间隔不低于2ms，每次耗时不超过1ms</code></p><p>②执行清理耗时不超过1ms</p><p>③逐个遍历db，逐个遍历db中的bucket，抽取20个key判断是否过期</p><p>④如果没达到时间上限（1ms）并且过期key比例大于10%，再进行一次抽样，否则结束</p><h4 id="定期扫描" tabindex="-1">定期扫描 <a class="header-anchor" href="#定期扫描" aria-label="Permalink to &quot;定期扫描&quot;">​</a></h4><blockquote><p>系统每隔一段时间就定期扫描一次，发现过期的键就进行删除。这种策略相对来说是上面两种策略的折中方案，需要注意的是这个定期的频率要结合实际情况掌控好，使用这种方案有一个缺陷就是可能会出现已经过期的键也被返回。</p></blockquote><h2 id="内存淘汰策略" tabindex="-1">内存淘汰策略 <a class="header-anchor" href="#内存淘汰策略" aria-label="Permalink to &quot;内存淘汰策略&quot;">​</a></h2><blockquote><p><strong>内存淘汰</strong>：就是当Redis内存使用达到设置的上限时，主动挑选<strong>部分key</strong>删除以释放更多内存的流程。Redis会在处理客户端命令的方法processCommand()中尝试做内存淘汰：</p></blockquote><h3 id="八大淘汰策略" tabindex="-1">八大淘汰策略 <a class="header-anchor" href="#八大淘汰策略" aria-label="Permalink to &quot;八大淘汰策略&quot;">​</a></h3><p><code>Redis</code> 中提供了 <code>8</code> 种淘汰策略</p><blockquote><p>注意：如果没有可删除的键对象，内存还是不够时，则报错</p></blockquote><table><thead><tr><th style="text-align:left;">淘汰策略</th><th style="text-align:left;">说明</th></tr></thead><tbody><tr><td style="text-align:left;">volatile-lru</td><td style="text-align:left;">对设置了TTL的key，基于LFI算法进行淘汰。</td></tr><tr><td style="text-align:left;">allkeys-lru</td><td style="text-align:left;">对全体key，基于LFU算法进行淘汰。</td></tr><tr><td style="text-align:left;">volatile-lfu</td><td style="text-align:left;">对设置了TTL的key，基于LRU算法进行淘汰。</td></tr><tr><td style="text-align:left;">allkeys-lfu</td><td style="text-align:left;">对全体key，基于LRU算法进行淘汰。</td></tr><tr><td style="text-align:left;">volatile-random</td><td style="text-align:left;">对设置了TTL的key ，随机进行淘汰。</td></tr><tr><td style="text-align:left;">allkeys-random</td><td style="text-align:left;">对全体key ，随机进行淘汰。</td></tr><tr><td style="text-align:left;">volatile-ttl</td><td style="text-align:left;">对设置了TTL的key，比较key的剩余TTL值，TTL越小越先被淘汰。</td></tr><tr><td style="text-align:left;">noeviction</td><td style="text-align:left;">默认策略，不淘汰任何key，但是内存满时不允许写入新数据，默认就是这种策略</td></tr></tbody></table><h3 id="lru和lfu分析" tabindex="-1">LRU和LFU分析 <a class="header-anchor" href="#lru和lfu分析" aria-label="Permalink to &quot;LRU和LFU分析&quot;">​</a></h3><p>比较容易混淆的有两个：</p><ul><li><p><strong>LRU</strong>（<strong>L</strong>east <strong>R</strong>ecently <strong>U</strong>sed），最少最近使用。用当前时间减去最后一次访问时间，这个值越大则淘汰优先级越高</p></li><li><p><strong>LFU</strong>（<strong>L</strong>east <strong>F</strong>requently <strong>U</strong>sed），最少频率使用。会统计每个key的访问频率，值越小淘汰优先级越高。</p></li></ul><h3 id="淘汰逻辑分析" tabindex="-1">淘汰逻辑分析 <a class="header-anchor" href="#淘汰逻辑分析" aria-label="Permalink to &quot;淘汰逻辑分析&quot;">​</a></h3><p>Redis的数据都会被封装为RedisObject结构：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.11/202206082242311.png" alt="image-20220608224248227" style="zoom:80%;"><p>LFU的访问次数之所以叫做<strong>逻辑访问次数</strong>，是因为并不是每次key被访问都计数，而是通过运算：</p><p>①生成0~1之间的随机数R</p><p>②计算 (旧次数 * lfu_log_factor + 1)，记录为P</p><p>③如果 R &lt; P ，则计数器 + 1，且最大不超过255</p><p>④访问次数会随时间衰减，距离上一次访问时间每隔 lfu_decay_time 分钟，计数器 -1</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.11/202206082243139.png" alt="image-20220608224342027" style="zoom:80%;"><h1 id="数据库和缓存双写一致性⭐⭐" tabindex="-1">数据库和缓存双写一致性⭐⭐ <a class="header-anchor" href="#数据库和缓存双写一致性⭐⭐" aria-label="Permalink to &quot;数据库和缓存双写一致性⭐⭐&quot;">​</a></h1><p><a href="https://mp.weixin.qq.com/s?__biz=MzU1NTkwODE4Mw==&amp;mid=2247502123&amp;idx=1&amp;sn=1471d2592156dd60274301845ea00188&amp;chksm=fbcfa413ccb82d05ffd6aa4655a8e984ad6ab886cceacfee50900a1b6d52ab5f9010aee0bd27&amp;mpshare=1&amp;scene=23&amp;srcid=0827QldybeWp7rBXVutzf2nS&amp;sharer_sharetime=1661578679538&amp;sharer_shareid=29b8a04db1dbd975e3bf4e9f47e7ac67#rd" target="_blank" rel="noreferrer">如何保证数据库和缓存双写一致性？ (qq.com)</a></p><p><a href="https://mp.weixin.qq.com/s?__biz=Mzg2NzYyNjQzNg==&amp;mid=2247486612&amp;idx=1&amp;sn=e3dabdbedafd33192095fdd33cb3c305&amp;chksm=ceb9f03ff9ce7929eb05aebc64a309ecb568ea1c6b5eca396a08f927f0eabec688122b7a3865&amp;scene=21#wechat_redirect" target="_blank" rel="noreferrer">数据库跟缓存的双写一致性 (qq.com)</a></p><p>数据库和缓存（比如：redis）双写数据一致性问题，是一个跟开发语言无关的公共问题。尤其在高并发的场景下，这个问题变得更加严重。</p><p>我很负责的告诉大家，该问题无论在面试，还是工作中遇到的概率非常大，所以非常有必要跟大家一起探讨一下。</p><p>今天这篇文章我会从浅入深，跟大家一起聊聊，数据库和缓存双写数据一致性问题常见的解决方案，这些方案中可能存在的坑，以及最优方案是什么。</p><h2 id="_1-一致性问题和常见方案" tabindex="-1">1. 一致性问题和常见方案 <a class="header-anchor" href="#_1-一致性问题和常见方案" aria-label="Permalink to &quot;1. 一致性问题和常见方案&quot;">​</a></h2><h3 id="_1-读取场景-没啥" tabindex="-1">1 读取场景(没啥) <a class="header-anchor" href="#_1-读取场景-没啥" aria-label="Permalink to &quot;1 读取场景(没啥)&quot;">​</a></h3><p>通常情况下，我们使用缓存的主要目的是为了提升查询的性能。大多数情况下，我们是这样使用缓存的：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208271511995.png" alt="image-20220827151102852" style="zoom:67%;"><blockquote><ol><li>用户请求过来之后，先查缓存有没有数据，如果有则直接返回。</li><li>如果缓存没数据，再继续查数据库。</li><li>如果数据库有数据，则将查询出来的数据，放入缓存中，然后返回该数据。</li><li>如果数据库也没数据，则直接返回空。</li></ol></blockquote><p>这是缓存非常常见的用法。一眼看上去，好像没有啥问题。</p><h3 id="_2-更新场景-问题不少" tabindex="-1">2 更新场景(问题不少) <a class="header-anchor" href="#_2-更新场景-问题不少" aria-label="Permalink to &quot;2 更新场景(问题不少)&quot;">​</a></h3><p>但你忽略一个非常重要地方：<strong>如果数据库中的某条数据，放入缓存之后，又立马被更新了，那么该如何更新缓存呢？</strong></p><p>不更新缓存行不行？</p><blockquote><p>答：当然不行，如果不更新缓存，在很长的一段时间内（决定于缓存的过期时间），用户请求从缓存中获取到的都可能是旧值，而非数据库的最新值。这不是有数据不一致的问题？</p></blockquote><p>更新过程之所以会出现数据不一致问题，有内外两大原因：</p><ul><li><strong>内部原因</strong>：Redis和MySQL的更新不是天然的原子操作，非事务性的组合拳。</li><li><strong>外部原因</strong>：实际中的读写请求是并发且无序的，可预测性很差，完全不可控。</li></ul><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202212101206827.png" alt="image-20221210120614723" style="zoom:50%;"><h3 id="_3-数据不一致的感知" tabindex="-1">3 数据不一致的感知 <a class="header-anchor" href="#_3-数据不一致的感知" aria-label="Permalink to &quot;3 数据不一致的感知&quot;">​</a></h3><p>我们来看个实际中的例子，进一步了解缓存系统的数据不一致问题。</p><p>平时上下班挤地铁的时候，我们经常会听网易云，比如我喜欢听民谣，所有会关注官方发布的一些民谣歌曲榜单</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202212101235365.png" alt="image-20221210123508196" style="zoom:67%;"><p>这是个非常典型的读多写少的场景，因为歌单是网易云的运营同学配置的，作为用户我们是无法修改的歌单的内容的。</p><p>所以假如我是网易云的后端同学，我肯定会把歌单的信息存储在Redis中，缓存下来提高性能，大概可以是这个样子：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202212101235992.png" alt="image-20221210123542862" style="zoom:80%;"><p>假如因为版权问题，运营删除了一首歌，此时更新了MySQL，但是如果Redis中的数据并没有及时被更新，那么就会有一部分用户在歌单中看到本已被删除的歌曲，点击时可能无法播放等。</p><blockquote><p><strong>画外音</strong>：这就是缓存和主存储的数据不一致的现象，当然具体网易云是咋实现的，咱也不清楚，上述的场景纯属作者脑补来说明不一致问题的直观实例。</p></blockquote><h3 id="_4-理性看待不一致问题" tabindex="-1">4 理性看待不一致问题 <a class="header-anchor" href="#_4-理性看待不一致问题" aria-label="Permalink to &quot;4 理性看待不一致问题&quot;">​</a></h3><p>数据一致性可以说是分布式系统中必然存在的问题，数据一致性可以分为：</p><ul><li><strong>强一致性</strong>：时时刻刻保持一致。</li><li><strong>最终一致性</strong>：允许短暂的不一致，但是最后还是一致的。</li></ul><p>要实现缓存和主存储的强一致性，需要借助于复杂的分布式一致性协议等，倒不如不用缓存，毕竟缓存的优势还是读多写少的场景。</p><blockquote><p><strong>画外音</strong>：缓存并不是什么万金油，对于写多读少的场景，或许并不是适合用缓存，劝大家不要唯缓存论。</p></blockquote><p>在工程上大部分场景下最终一致性就足够了，因此我们将问题转化为：</p><blockquote><p><strong>在保证数据最终一致性的前提下，如何把数据不一致带来的影响降低到业务可接受的范围内。</strong></p></blockquote><h3 id="_5-更新还是删除是个问题" tabindex="-1">5 更新还是删除是个问题 <a class="header-anchor" href="#_5-更新还是删除是个问题" aria-label="Permalink to &quot;5 更新还是删除是个问题&quot;">​</a></h3><p>当MySQL被更新时，我们如何处理Redis中的老数据呢？</p><p>江湖上有两种常见的做法，我们一起来看看：</p><ul><li><code>删除操作</code>：直接将key淘汰掉，是否再次被加载由后续读请求决定，本次只负责删除，只管杀不管埋。</li><li><code>更新操作</code>：直接update发生变化的key，相当于帮后面的请求做了加载的操作，管杀管埋。</li></ul><p>可以明确一点删除操作直接操作就行，但是更新操作可能涉及的处理步骤更多，也就是update比delete更复杂。</p><p>还有一点，我们需要尽量保证Redis中的数据都是热数据，update每次都会使得数据驻留在Redis中，或许这是没有必要的，因为这些可能是冷数据，至于要加载哪些数据，还是交给后面的请求比较合适。</p><p>综上，我们更倾向于将delete操作作为通用的选择，因此文章后续都是基于删除缓存的策略来展开的。</p><h3 id="_6-如何解决不一致问题" tabindex="-1">6 如何解决不一致问题 <a class="header-anchor" href="#_6-如何解决不一致问题" aria-label="Permalink to &quot;6 如何解决不一致问题&quot;">​</a></h3><p>那么，我们该如何更新缓存呢？目前有以下4种方案：</p><ol><li>先写缓存，再写数据库</li><li>先写数据库，再写缓存</li><li>先删缓存，再写数据库</li><li>先写数据库，再删缓存</li></ol><p>接下来，我们详细说说这4种方案。</p><h2 id="_2-先写缓存-再写数据库-不可取" tabindex="-1">2. 先写缓存，再写数据库(不可取) <a class="header-anchor" href="#_2-先写缓存-再写数据库-不可取" aria-label="Permalink to &quot;2. 先写缓存，再写数据库(不可取)&quot;">​</a></h2><p>对于更新缓存的方案，很多人第一个想到的可能是在写操作中直接更新缓存（写缓存），更直接明了。</p><p>那么，问题来了：在写操作中，到底是先写缓存，还是先写数据库呢？</p><p>我们在这里先聊聊先写缓存，再写数据库的情况，因为它的问题最严重。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208271512438.png" alt="image-20220827151229350" style="zoom:67%;"><p>某一个用户的每一次写操作，如果刚写完缓存，突然网络出现了异常，导致写数据库失败了。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208271512445.png" alt="image-20220827151246351" style="zoom:67%;"><p>其结果是缓存更新成了最新数据，但数据库没有，这样缓存中的数据不就变成脏数据了？如果此时该用户的查询请求，正好读取到该数据，就会出现问题，因为该数据在数据库中根本不存在，这个问题非常严重。</p><p>我们都知道，缓存的主要目的是把数据库的数据临时保存在内存，便于后续的查询，提升查询速度。</p><p>但如果某条数据，在数据库中都不存在，你缓存这种“<code>假数据</code>”又有啥意义呢？</p><p>因此，先写缓存，再写数据库的方案是不可取的，在实际工作中用得不多。</p><h2 id="_3-先写数据库-再写缓存-不可取" tabindex="-1">3. 先写数据库，再写缓存(不可取) <a class="header-anchor" href="#_3-先写数据库-再写缓存-不可取" aria-label="Permalink to &quot;3. 先写数据库，再写缓存(不可取)&quot;">​</a></h2><p>既然上面的方案行不通，接下来，聊聊先写数据库，再写缓存的方案，该方案在低并发编程中有人在用（我猜的）。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202212101423024.png" alt="image-20221210142310914" style="zoom:50%;"><p>这种模式在更新MySQL和淘汰Redis这段时间内，请求读取的还是Redis的旧数据，不过等MySQL更新完成，就可以立刻恢复一致，影响相对比较小。</p><p>但是，假如T0时刻读取的数据在缓存没有，那么触发Cache Miss后会产生回写，假如这个回写动作是在T4时刻完成，那么写入的还是老数据，如图：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202212101424954.png" alt="image-20221210142444846" style="zoom:80%;"><p>用户的写操作，先写数据库，再写缓存，可以避免之前“假数据”的问题。但它却带来了新的问题。什么问题呢？</p><p>这种情况确实有问题，但是真是好巧不巧：</p><ul><li>事件A：更新MySQL前出现一个读请求，且缓存中无数据出现cache miss</li><li>事件B：T3时刻回写Redis的操作才完成，在此之前T2时刻清除了缓存</li></ul><p>那么发生问题的概率就是P(A)*P(B)，从实际考虑这种综合事件发生的概率非常低，因为写操作远慢于读操作。</p><p>也就是实际场景中上图中更新MySQL&amp;淘汰缓存的操作耗时更久，可以把之前回写到Redis老数据给清除掉。</p><blockquote><p><strong>画外音</strong>：先更新MySQL再淘汰Redis的方案，虽然存在小概率不一致问题，但是总体来说工程上是可用的，比如非要说写完MySQL挂了，Redis就没淘汰，这种情况只能说确实有问题。</p></blockquote><h3 id="_1-写缓存失败了" tabindex="-1">1 写缓存失败了 <a class="header-anchor" href="#_1-写缓存失败了" aria-label="Permalink to &quot;1 写缓存失败了&quot;">​</a></h3><p>如果把写数据库和写缓存操作，放在同一个事务当中，当写缓存失败了，我们可以把写入数据库的数据进行回滚。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208271513713.png" alt="image-20220827151330625" style="zoom:67%;"><p>如果是并发量比较小，对接口性能要求不太高的系统，可以这么玩。</p><p>但如果在高并发的业务场景中，写数据库和写缓存，都属于远程操作。为了防止出现大事务，造成的死锁问题，通常建议写数据库和写缓存不要放在同一个事务中。</p><p>也就是说在该方案中，如果写数据库成功了，但写缓存失败了，数据库中已写入的数据不会回滚。</p><p>这就会出现：数据库是<code>新数据</code>，而缓存是<code>旧数据</code>，两边<code>数据不一致</code>的情况。</p><h3 id="_2-高并发下的问题" tabindex="-1">2 高并发下的问题 <a class="header-anchor" href="#_2-高并发下的问题" aria-label="Permalink to &quot;2 高并发下的问题&quot;">​</a></h3><p>假设在高并发的场景中，针对同一个用户的同一条数据，有两个写数据请求：a和b，它们同时请求到业务系统。</p><p>其中请求a获取的是旧数据，而请求b获取的是新数据，如下图所示：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208271513572.png" alt="image-20220827151347464" style="zoom:80%;"><ol><li>请求a先过来，刚写完了数据库。但由于网络原因，卡顿了一下，还没来得及写缓存。</li><li>这时候请求b过来了，先写了数据库。</li><li>接下来，请求b顺利写了缓存。</li><li>此时，请求a卡顿结束，也写了缓存。</li></ol><p>很显然，在这个过程当中，请求b在缓存中的<code>新数据</code>，被请求a的<code>旧数据</code>覆盖了。</p><p>也就是说：在高并发场景中，如果多个线程同时执行先写数据库，再写缓存的操作，可能会出现数据库是新值，而缓存中是旧值，两边数据不一致的情况。</p><h3 id="_3-浪费系统资源" tabindex="-1">3 浪费系统资源 <a class="header-anchor" href="#_3-浪费系统资源" aria-label="Permalink to &quot;3 浪费系统资源&quot;">​</a></h3><p>该方案还有一个比较大的问题就是：每个写操作，写完数据库，会马上写缓存，比较<code>浪费系统资源</code>。</p><p>为什么这么说呢？你可以试想一下，如果写的缓存，并不是简单的数据内容，而是要经过非常复杂的计算得出的最终结果。这样每写一次缓存，都需要经过一次非常复杂的计算，不是非常浪费系统资源吗？</p><p>尤其是<code>cpu</code>和<code>内存</code>资源。还有些业务场景比较特殊：<code>写多读少</code>。如果在这类业务场景中，每个用的写操作，都需要写一次缓存，有点得不偿失。由此可见，在高并发的场景中，先写数据库，再写缓存，这套方案问题挺多的，也不太建议使用。如果你已经用了，赶紧看看踩坑了没？</p><h2 id="_4-先删缓存-再写数据库" tabindex="-1">4. 先删缓存，再写数据库 <a class="header-anchor" href="#_4-先删缓存-再写数据库" aria-label="Permalink to &quot;4. 先删缓存，再写数据库&quot;">​</a></h2><p>通过上面的内容我们得知，如果直接更新缓存的问题很多。那么，为何我们不能换一种思路：不去直接更新缓存，而改为删除缓存呢？删除缓存方案，同样有两种：</p><blockquote><ol><li>先删缓存，再写数据库</li><li>先写数据库，再删缓存</li></ol></blockquote><p>我们一起先看看：先删缓存，再写数据库的情况。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202212101428920.png" alt="image-20221210142830808" style="zoom:50%;"><ul><li>在T1时刻：Redis和MySQL对于age的值都是18，二者一致;</li><li>在T2时刻：有更新请求需要设置age=20，此时Redis中就没有age这个数据了；在完成Redis淘汰后，进行MySQL数据更新age=20;</li></ul><p>这个方案听着还不错的样子，但是读写请求都是并发的，先后顺序完全无法预测，甚至后发出的请求先处理完成，也是很常见的。</p><p>因此就造成一个明显的漏洞：在淘汰Redis的数据完成后，更新MySQL完成之前，这个时间段内如果有新的读请求过来，发现Cache Miss了，就会把旧数据重新写到Redis中，再次造成不一致，并且毫无察觉后续读的都是旧数据。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202212101429745.png" alt="image-20221210142923605" style="zoom:50%;"><p>说白了，在用户的写操作中，先执行删除缓存操作，再去写数据库。这套方案，可以是可以，但也会有一样问题。</p><blockquote><p><strong>画外音</strong>：这个方案其实不能说完全没有用，但是至少不完美吧，还可以再想想别的方案。</p></blockquote><p>高并发下的问题</p><p>假设在高并发的场景中，同一个用户的同一条数据，有一个读数据请求c，还有另一个写数据请求d（一个更新操作），同时请求到业务系统。如下图所示：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208271514642.png" alt="image-20220827151436524" style="zoom:80%;"><ol><li>请求d先过来，把缓存删除了。但由于网络原因，卡顿了一下，还没来得及写数据库。</li><li>这时请求c过来了，先查缓存发现没数据，再查数据库，有数据，但是旧值。</li><li>请求c将数据库中的旧值，更新到缓存中。</li><li>此时，请求d卡顿结束，把新值写入数据库。</li></ol><p>在这个过程当中，请求d的新值并没有被请求c写入缓存，同样会导致缓存和数据库的数据不一致的情况。更正：图中步骤7写入旧值，步骤9要删掉。</p><p>那么，这种场景的数据不一致问题，能否解决呢？</p><h2 id="_5-延时双删" tabindex="-1">5 延时双删 <a class="header-anchor" href="#_5-延时双删" aria-label="Permalink to &quot;5 延时双删&quot;">​</a></h2><p>在上面的业务场景中，一个读数据请求，一个写数据请求。当写数据请求把缓存删了之后，读数据请求，可能把当时从数据库查询出来的旧值，写入缓存当中。</p><p>有人说还不好办，请求d在写完数据库之后，把缓存重新删一次不就行了？</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202212101420437.png" alt="image-20221210142027332" style="zoom:80%;"><blockquote><p>这就是我们所说的<code>缓存双删</code>，即在写数据库之前删除一次，写完数据库后，再删除一次。</p></blockquote><blockquote><p>该方案有个非常关键的地方是：第二次删除缓存，并非立马就删，而是要在一定的<code>时间间隔</code>之后。</p></blockquote><p>我们再重新回顾一下，高并发下一个读数据请求，一个写数据请求导致数据不一致的产生过程：</p><blockquote><ol><li>请求d先过来，把缓存删除了。但由于网络原因，卡顿了一下，还没来得及写数据库。</li><li>这时请求c过来了，先查缓存发现没数据，再查数据库，有数据，但是旧值。</li><li>请求c将数据库中的旧值，更新到缓存中。</li><li>此时，请求d卡顿结束，把新值写入数据库。</li><li>一段时间之后，比如：500ms，请求d将缓存删除。</li></ol></blockquote><p>这样来看确实可以解决缓存不一致问题。</p><p><strong>那么，为什么一定要间隔一段时间之后，才能删除缓存呢？</strong></p><blockquote><p>请求d卡顿结束，把新值写入数据库后，请求c将数据库中的旧值，更新到缓存中。</p></blockquote><blockquote><p>此时，如果请求d删除太快，在请求c将数据库中的旧值更新到缓存之前，就已经把缓存删除了，这次删除就没任何意义。必须要在请求c更新缓存之后，再删除缓存，才能把旧值及时删除了。</p></blockquote><blockquote><p>所以需要在请求d中加一个时间间隔，确保请求c，或者类似于请求c的其他请求，如果在缓存中设置了旧值，最终都能够被请求d删除掉。</p></blockquote><p><strong>接下来，还有一个问题：如果第二次删除缓存时，删除失败了该怎么办？</strong></p><p>这里先留点悬念，后面会详细说。</p><blockquote><p>说实话个人觉得，这个方案有点堆操作的感觉，而且设置延时的目的是为了避免思路三的小概率问题，延时设置多久不好确定，二来延时降低了并发性能，同时前置的删除缓存操作起到的作用并不大。</p></blockquote><p>这个方案倒是透露出一种思想：多删几次，可能一致性更有保证，那确实如此。</p><blockquote><p><strong>画外音</strong>：这个方案也不是说不行，其实有点麻烦，并且在复杂高并发场景中反而影响性能，要是一般的场景或许也能用起来。</p></blockquote><h2 id="_5-先写数据库-再删缓存" tabindex="-1">5. 先写数据库，再删缓存 <a class="header-anchor" href="#_5-先写数据库-再删缓存" aria-label="Permalink to &quot;5. 先写数据库，再删缓存&quot;">​</a></h2><p>从前面得知，先删缓存，再写数据库，在并发的情况下，也可能会出现缓存和数据库的数据不一致的情况。</p><p>那么，我们只能寄希望于最后的方案了。</p><p>接下来，我们重点看看先写数据库，再删缓存的方案。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208271515125.png" alt="image-20220827151519033" style="zoom:67%;"><p>在高并发的场景中，有一个读数据请求，有一个写数据请求，更新过程如下：</p><ol><li>请求e先写数据库，由于网络原因卡顿了一下，没有来得及删除缓存。</li><li>请求f查询缓存，发现缓存中有数据，直接返回该数据。</li><li>请求e删除缓存。</li></ol><p>在这个过程中，只有请求f读了一次旧数据，后来旧数据被请求e及时删除了，看起来问题不大。</p><p>但如果是读数据请求先过来呢？</p><ol><li>请求f查询缓存，发现缓存中有数据，直接返回该数据。</li><li>请求e先写数据库。</li><li>请求e删除缓存。</li></ol><p>这种情况看起来也没问题呀？</p><p>答：对的。</p><p>但就怕出现下面这种情况，即缓存自己失效了。如下图所示：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208271515453.png" alt="image-20220827151541329" style="zoom:80%;"><ol><li>缓存过期时间到了，自动失效。</li><li>请求f查询缓存，发缓存中没有数据，查询数据库的旧值，但由于网络原因卡顿了，没有来得及更新缓存。</li><li>请求e先写数据库，接着删除了缓存。</li><li>请求f更新旧值到缓存中。</li></ol><p>这时，缓存和数据库的数据同样出现不一致的情况了。</p><p>但这种情况还是比较少的，需要同时满足以下条件才可以：</p><ol><li>缓存刚好自动失效。</li><li>请求f从数据库查出旧值，更新缓存的耗时，比请求e写数据库，并且删除缓存的还长。</li></ol><p>我们都知道查询数据库的速度，一般比写数据库要快，更何况写完数据库，还要删除缓存。所以绝大多数情况下，写数据请求比读数据情况耗时更长。</p><p>由此可见，系统同时满足上述两个条件的概率非常小。</p><blockquote><p>推荐大家使用先写数据库，再删缓存的方案，虽说不能100%避免数据不一致问题，但出现该问题的概率，相对于其他方案来说是最小的。</p></blockquote><p>但在该方案中，如果删除缓存失败了该怎么办呢？</p><h2 id="_6-删缓存失败怎么办" tabindex="-1">6. 删缓存失败怎么办？ <a class="header-anchor" href="#_6-删缓存失败怎么办" aria-label="Permalink to &quot;6. 删缓存失败怎么办？&quot;">​</a></h2><p>其实先写数据库，再删缓存的方案，跟缓存双删的方案一样，有一个共同的风险点，即：如果缓存删除失败了，也会导致缓存和数据库的数据不一致。</p><p>那么，删除缓存失败怎么办呢？</p><p>答：需要加<code>重试机制</code>。</p><p>在接口中如果更新了数据库成功了，但更新缓存失败了，可以立刻重试3次。如果其中有任何一次成功，则直接返回成功。如果3次都失败了，则写入数据库，准备后续再处理。</p><p>当然，如果你在接口中直接<code>同步重试</code>，该接口并发量比较高的时候，可能有点影响接口性能。</p><p>这时，就需要改成<code>异步重试</code>了。</p><p>异步重试方式有很多种，比如：</p><ol><li>每次都单独起一个线程，该线程专门做重试的工作。但如果在高并发的场景下，可能会创建太多的线程，导致系统OOM问题，不太建议使用。</li><li>将重试的任务交给线程池处理，但如果服务器重启，部分数据可能会丢失。</li><li>将重试数据写表，然后使用elastic-job等定时任务进行重试。</li><li>将重试的请求写入mq等消息中间件中，在mq的consumer中处理。</li><li>订阅mysql的binlog，在订阅者中，如果发现了更新数据请求，则删除相应的缓存。</li></ol><h2 id="_7-定时任务" tabindex="-1">7. 定时任务 <a class="header-anchor" href="#_7-定时任务" aria-label="Permalink to &quot;7. 定时任务&quot;">​</a></h2><p>使用<code>定时任务重试</code>的具体方案如下：</p><ol><li>当用户操作写完数据库，但删除缓存失败了，需要将用户数据写入重试表中。如下图所示：</li></ol><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208271516673.png" alt="image-20220827151623477" style="zoom:50%;"><ol><li>在定时任务中，异步读取重试表中的用户数据。重试表需要记录一个重试次数字段，初始值为0。然后重试5次，不断删除缓存，每重试一次该字段值+1。如果其中有任意一次成功了，则返回成功。如果重试了5次，还是失败，则我们需要在重试表中记录一个失败的状态，等待后续进一步处理。</li></ol><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208271516828.png" alt="image-20220827151641624" style="zoom:50%;"><ol><li>在高并发场景中，定时任务推荐使用<code>elastic-job</code>。相对于xxl-job等定时任务，它可以分片处理，提升处理速度。同时每片的间隔可以设置成：1,2,3,5,7秒等。</li></ol><p>使用定时任务重试的话，有个缺点就是实时性没那么高，对于实时性要求特别高的业务场景，该方案不太适用。但是对于一般场景，还是可以用一用的。</p><p>但它有一个很大的优点，即数据是落库的，不会丢数据。</p><h2 id="_8-mq" tabindex="-1">8. mq <a class="header-anchor" href="#_8-mq" aria-label="Permalink to &quot;8. mq&quot;">​</a></h2><p>既然直接操作MySQL和Redis都多少存在一些问题，那么能不能引入中间层来解决问题呢？</p><blockquote><p>把MySQL的更新操作完成后不直接操作Redis，而是把这个操作命令(消息)扔到一个中间层，然后由Redis自己来消费更新数据，这是一种解耦的异步方案。</p></blockquote><blockquote><p>在高并发的业务场景中，mq（消息队列）是必不可少的技术之一。它不仅可以异步解耦，还能削峰填谷。对保证系统的稳定性是非常有意义的。</p></blockquote><blockquote><p>mq的生产者，生产了消息之后，通过指定的topic发送到mq服务器。然后mq的消费者，订阅该topic的消息，读取消息数据之后，做业务逻辑处理。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202212101242431.png" alt="image-20221210124209303" style="zoom:67%;"><p>单纯为了更新缓存引入中间件确实有些复杂，但是像MySQL提供了binlog的同步机制，此时Redis就作为Slave进行主从同步，实现数据的更新，成本也还可以接受。</p><blockquote><p><strong>画外音</strong>：引入中间层思想真是万金油啊！</p></blockquote><p>使用<code>mq重试</code>的具体方案如下：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208271517664.png" alt="image-20220827151722460" style="zoom:67%;"><ol><li>当用户操作写完数据库，但删除缓存失败了，产生一条mq消息，发送给mq服务器。</li><li>mq消费者读取mq消息，重试5次删除缓存。如果其中有任意一次成功了，则返回成功。如果重试了5次，还是失败，则写入<code>死信队列</code>中。</li><li>推荐mq使用<code>rocketmq</code>，重试机制和死信队列默认是支持的。使用起来非常方便，而且还支持顺序消息，延迟消息和事务消息等多种业务场景。</li></ol><p>当然在该方案中，删除缓存可以完全走异步。即用户的写操作，在写完数据库之后，不用立刻删除一次缓存。而直接发送mq消息，到mq服务器，然后有mq消费者全权负责删除缓存的任务。</p><p>因为mq的实时性还是比较高的，因此改良后的方案也是一种不错的选择。</p><h2 id="_9-binlog-mq⭐" tabindex="-1">9. binlog+mq⭐ <a class="header-anchor" href="#_9-binlog-mq⭐" aria-label="Permalink to &quot;9. binlog+mq⭐&quot;">​</a></h2><p>前面我们聊过的，无论是定时任务，还是mq（消息队列），做重试机制，对业务都有一定的侵入性。</p><p>在使用定时任务的方案中，需要在业务代码中增加额外逻辑，如果删除缓存失败，需要将数据写入重试表。</p><p>而使用mq的方案中，如果删除缓存失败了，需要在业务代码中发送mq消息到mq服务器。</p><p>其实，还有一种更优雅的实现，即<code>监听binlog</code>，比如使用：<code>canal</code>等中间件。</p><p>具体方案如下：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208271520146.png" alt="image-20220827152052994" style="zoom:80%;"><ol><li>在业务接口中写数据库之后，就不管了，直接返回成功。</li><li>mysql服务器会自动把变更的数据写入binlog中。</li><li>binlog订阅者获取变更的数据，然后删除缓存。</li></ol><p>这套方案中业务接口确实简化了一些流程，只用关心数据库操作即可，而在binlog订阅者中做缓存删除工作。</p><p>但如果只是按照图中的方案进行删除缓存，只删除了一次，也可能会失败。</p><p>如何解决这个问题呢？</p><p>答：这就需要加上前面聊过的<code>重试机制</code>了。如果删除缓存失败，写入重试表，使用定时任务重试。或者写入mq，让mq自动重试。</p><p>在这里推荐使用<code>mq自动重试机制</code>。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208271521917.png" alt="image-20220827152112739" style="zoom:80%;"><p>在binlog订阅者中如果删除缓存失败，则发送一条mq消息到mq服务器，在mq消费者中自动重试5次。如果有任意一次成功，则直接返回成功。如果重试5次后还是失败，则该消息自动被放入死信队列，后面可能需要人工介入。</p><h2 id="_10-设置缓存过期时间" tabindex="-1">10 设置缓存过期时间 <a class="header-anchor" href="#_10-设置缓存过期时间" aria-label="Permalink to &quot;10 设置缓存过期时间&quot;">​</a></h2><p>当向Redis写入一条数据时，同时设置过期时间x秒，业务不同过期时间不同。</p><p>过期时间到达时Redis就会删掉这条数据，后续读请求Redis出现Cache Miss，进而读取MySQL，然后把数据写到Redis。</p><p>如果发生更新操作时，只操作MySQL，那么Redis中的数据更新就只是依赖于过期时间来保底。</p><p>换句话说：如果某个key的数据目前在缓存中，当数据发生更新时，只写MySQL并不写Redis，在更新数据后且缓存过期前的这段时间内，读取的数据是不一致的。</p><blockquote><p><strong>画外音</strong>：这种方案是最简单的，如果业务对短时间不一致问题并不在意，设置过期时间的方案就足够了，没有必要搞太复杂。</p></blockquote><h1 id="缓存更新策略" tabindex="-1">缓存更新策略 <a class="header-anchor" href="#缓存更新策略" aria-label="Permalink to &quot;缓存更新策略&quot;">​</a></h1><p>标题也可以是：<code>高并发场景下，先更新缓存还是先更新数据库</code></p><p>在大型系统中，为了减少数据库压力通常会引入缓存机制，一旦引入缓存又很容易造成缓存和数据库数据不一致，导致用户看到的是旧数据。</p><p><code>为了减少数据不一致的情况，更新缓存和数据库的机制显得尤为重要</code>，接下来带领大家踩踩坑。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207231947646.png" alt="image-20220723194703557" style="zoom:67%;"><h2 id="cache-aside" tabindex="-1">Cache aside <a class="header-anchor" href="#cache-aside" aria-label="Permalink to &quot;Cache aside&quot;">​</a></h2><p><code>Cache aside</code>也就是<code>旁路缓存</code>，是比较常用的缓存策略。</p><p><strong>（1）<code>读请求</code>常见流程</strong></p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207231949600.png" alt="image-20220723194928495" style="zoom:33%;"><p>应用首先会判断缓存是否有该数据，缓存命中直接返回数据，缓存未命中即缓存穿透到数据库，从数据库查询数据然后回写到缓存中，最后返回数据给客户端。</p><p><strong>（2）<code>写请求</code>常见流程</strong></p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207231950309.png" alt="image-20220723195003237" style="zoom:40%;"><p>首先更新数据库，然后从缓存中删除该数据。</p><p>看了写请求的图之后，有些同学可能要问了：为什么要删除缓存，直接更新不就行了？这里涉及到几个坑，我们一步一步踩下去。</p><h2 id="cache-aside踩坑" tabindex="-1">Cache aside踩坑 <a class="header-anchor" href="#cache-aside踩坑" aria-label="Permalink to &quot;Cache aside踩坑&quot;">​</a></h2><p>Cache aside策略如果用错就会遇到深坑，下面我们来逐个踩。</p><p><strong>踩坑一：先更新数据库，再更新缓存</strong></p><p>如果同时有两个<code>写请求</code>需要更新数据，每个写请求都先更新数据库再更新缓存，在并发场景可能会出现数据不一致的情况。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207232047536.png" alt="image-20220723204755432" style="zoom:50%;"><p>先更新数据库，再更新缓存</p><p>如上图的执行过程：</p><p>（1）<code>写请求1</code>更新数据库，将 age 字段更新为18；</p><p>（2）<code>写请求2</code>更新数据库，将 age 字段更新为20；</p><p>（3）<code>写请求2</code>更新缓存，缓存 age 设置为20；</p><p>（4）<code>写请求1</code>更新缓存，缓存 age 设置为18；</p><p>执行完预期结果是数据库 age 为20，缓存 age 为20，结果缓存 age为18，这就造成了缓存数据不是最新的，出现了脏数据。</p><p><strong>踩坑二：先删缓存，再更新数据库</strong></p><p>如果<code>写请求</code>的处理流程是<code>先删缓存再更新数据库</code>，在一个<code>读请求</code>和一个<code>写请求</code>并发场景下可能会出现数据不一致情况。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207232049613.png" alt="image-20220723204916505" style="zoom:50%;"><p>先删缓存，再更新数据库</p><p>如上图的执行过程：</p><p>（1）<code>写请求</code>删除缓存数据；</p><p>（2）<code>读请求</code>查询缓存未击中(Hit Miss)，紧接着查询数据库，将返回的数据回写到缓存中；</p><p>（3）<code>写请求</code>更新数据库。</p><p>整个流程下来发现<code>数据库</code>中age为20，<code>缓存</code>中age为18，缓存和数据库数据不一致，缓存出现了脏数据。</p><p><strong>踩坑三：先更新数据库，再删除缓存</strong></p><p>在实际的系统中针对<code>写请求</code>还是推荐<code>先更新数据库再删除缓存</code>，但是在理论上还是存在问题，以下面这个例子说明。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207232051323.png" alt="image-20220723205153202" style="zoom:50%;"><p>先更新数据库，再删除缓存</p><p>如上图的执行过程：</p><p>（1）<code>读请求</code>先查询缓存，缓存未击中，查询数据库返回数据；</p><p>（2）<code>写请求</code>更新数据库，删除缓存；</p><p>（3）<code>读请求</code>回写缓存；</p><p>整个流程操作下来发现<code>数据库age为20</code>，<code>缓存age为18</code>，即数据库与缓存不一致，导致应用程序从缓存中读到的数据都为旧数据。</p><p>但我们仔细想一下，上述问题发生的概率其实非常低，因为通常数据库更新操作比内存操作耗时多出几个数量级，上图中最后一步回写缓存（set age 18）速度非常快，通常会在更新数据库之前完成。</p><p>如果这种极端场景出现了怎么办？我们得想一个兜底的办法：<code>缓存数据设置过期时间</code>。通常在系统中是可以允许少量的数据短时间不一致的场景出现。</p><h2 id="read-through" tabindex="-1">Read through <a class="header-anchor" href="#read-through" aria-label="Permalink to &quot;Read through&quot;">​</a></h2><p>在 Cache Aside 更新模式中，应用代码需要维护两个数据源头：一个是缓存，一个是数据库。而在 <code>Read-Through</code> 策略下，应用程序无需管理缓存和数据库，只需要将数据库的同步委托给缓存提供程序 <code>Cache Provider</code> 即可。所有数据交互都是通过<code>抽象缓存层</code>完成的。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207232052118.png" alt="image-20220723205226008" style="zoom:67%;"><p>如上图，应用程序只需要与<code>Cache Provider</code>交互，不用关心是从缓存取还是数据库。</p><p>在进行大量读取时，<code>Read-Through</code> 可以减少数据源上的负载，也对缓存服务的故障具备一定的弹性。如果缓存服务挂了，则缓存提供程序仍然可以通过直接转到数据源来进行操作。</p><p><code>Read-Through 适用于多次请求相同数据的场景</code>，这与 Cache-Aside 策略非常相似，但是二者还是存在一些差别，这里再次强调一下：</p><ul><li>在 Cache-Aside 中，应用程序负责从数据源中获取数据并更新到缓存。</li><li>在 Read-Through 中，此逻辑通常是由独立的缓存提供程序（Cache Provider）支持。</li></ul><h2 id="write-through" tabindex="-1">Write through <a class="header-anchor" href="#write-through" aria-label="Permalink to &quot;Write through&quot;">​</a></h2><p><code>Write-Through</code> 策略下，当发生数据更新(Write)时，缓存提供程序 <code>Cache Provider</code> 负责更新底层数据源和缓存。</p><p>缓存与数据源保持一致，并且写入时始终通过<code>抽象缓存层</code>到达数据源。</p><p><code>Cache Provider</code>类似一个代理的作用。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207232052517.png" alt="image-20220723205245424" style="zoom:67%;"><h2 id="write-behind" tabindex="-1">Write behind <a class="header-anchor" href="#write-behind" aria-label="Permalink to &quot;Write behind&quot;">​</a></h2><p><code>Write behind</code>在一些地方也被成为<code>Write back</code>， 简单理解就是：应用程序更新数据时只更新缓存， <code>Cache Provider</code>每隔一段时间将数据刷新到数据库中。说白了就是<code>延迟写入</code>。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.30/202207232053999.png" alt="image-20220723205311901" style="zoom:67%;"><p>如上图，应用程序更新两个数据，Cache Provider 会立即写入缓存中，但是隔一段时间才会批量写入数据库中。</p><p>这种方式有优点也有缺点：</p><ul><li><code>优点</code>是数据写入速度非常快，适用于频繁写的场景。</li><li><code>缺点</code>是缓存和数据库不是强一致性，对一致性要求高的系统慎用。</li></ul><p>总结一下</p><p>学了这么多，相信大家对缓存更新的策略都已经有了清晰的认识。最后稍稍总结一下。</p><p>缓存更新的策略主要分为三种：</p><ul><li>Cache aside</li><li>Read/Write through</li><li>Write behind</li></ul><p>Cache aside 通常会先更新数据库，然后再删除缓存，为了兜底通常还会将数据设置缓存时间。</p><p>Read/Write through 一般是由一个 Cache Provider 对外提供读写操作，应用程序不用感知操作的是缓存还是数据库。</p><p>Write behind简单理解就是延迟写入，Cache Provider 每隔一段时间会批量输入数据库，优点是应用程序写入速度非常快。</p><h1 id="redis-阻塞情况" tabindex="-1">Redis 阻塞情况 <a class="header-anchor" href="#redis-阻塞情况" aria-label="Permalink to &quot;Redis 阻塞情况&quot;">​</a></h1><h2 id="命令阻塞" tabindex="-1">命令阻塞 <a class="header-anchor" href="#命令阻塞" aria-label="Permalink to &quot;命令阻塞&quot;">​</a></h2><p>使用不当的命令造成客户端阻塞：</p><ul><li>keys * ：获取所有的 key 操作；</li><li>Hgetall：返回哈希表中所有的字段和；</li><li>smembers：返回集合中的所有成员；</li></ul><p>这些命令时间复杂度是O(n)，有时候也会全表扫描，随着n的增大耗时也会越大从而导致客户端阻塞。</p><h2 id="save-阻塞" tabindex="-1">SAVE 阻塞 <a class="header-anchor" href="#save-阻塞" aria-label="Permalink to &quot;SAVE 阻塞&quot;">​</a></h2><p>大家都知道 Redis 在进行 RDB 快照的时候，会调用系统函数 fork() ，创建一个子线程来完成临时文件的写入，而触发条件正是配置文件中的 save 配置。</p><p>当达到我们的配置时，就会触发 bgsave 命令创建快照，这种方式是不会阻塞主线程的，而手动执行 save 命令会在主线程中执行，<strong>阻塞</strong>主线程。</p><h2 id="同步持久化" tabindex="-1">同步持久化 <a class="header-anchor" href="#同步持久化" aria-label="Permalink to &quot;同步持久化&quot;">​</a></h2><p>当 Redis 直接记录 AOF 日志时，如果有大量的写操作，并且配置为同步持久化</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">appendfsync always</span></span></code></pre></div><p>即每次发生数据变更会被立即记录到磁盘，因为写磁盘比较耗时，性能较差，所以有时会阻塞主线程。</p><h2 id="aof-重写" tabindex="-1">AOF 重写 <a class="header-anchor" href="#aof-重写" aria-label="Permalink to &quot;AOF 重写&quot;">​</a></h2><ol><li>fork 出一条子线程来将文件重写，在执行 <code>BGREWRITEAOF</code> 命令时，Redis 服务器会维护一个 AOF 重写缓冲区，该缓冲区会在子线程创建新 AOF 文件期间，记录服务器执行的所有写命令。</li><li>当子线程完成创建新 AOF 文件的工作之后，服务器会将重写缓冲区中的所有内容追加到新 AOF 文件的末尾，使得新的 AOF 文件保存的数据库状态与现有的数据库状态一致。</li><li>最后，服务器用新的 AOF 文件替换旧的 AOF 文件，以此来完成 AOF 文件重写操作。</li></ol><p>阻塞就是出现在第2步的过程中，将缓冲区中新数据写到新文件的过程中会产生<strong>阻塞</strong>。</p><h2 id="aof-日志" tabindex="-1">AOF 日志 <a class="header-anchor" href="#aof-日志" aria-label="Permalink to &quot;AOF 日志&quot;">​</a></h2><p>AOF 的日志记录不像关系型数据库那样在执行命令之前记录日志（方便故障恢复），而是采用先执行命令后记录日志的方式。</p><p>原因就是 AOF 记录日志是不会对命令进行语法检查的，这样就能减少额外的检查开销，不会对当前命令的执行产生阻塞，但可能会给下一个操作带来阻塞风险。</p><p><strong>这是因为 AOF 日志也是在主线程中执行的</strong>，如果在把日志文件写入磁盘时，磁盘写压力大，就会导致写盘很慢，进而导致后续的操作也无法执行了。</p><h2 id="大-key-问题" tabindex="-1">大 Key 问题 <a class="header-anchor" href="#大-key-问题" aria-label="Permalink to &quot;大 Key 问题&quot;">​</a></h2><p>大 key 并不是指 key 的值很大，而是 key 对应的 value 很大。</p><p>大 key 造成的阻塞问题如下：</p><ul><li>客户端超时阻塞：由于 Redis 执行命令是单线程处理，然后在操作大 key 时会比较耗时，那么就会阻塞 Redis，从客户端这一视角看，就是很久很久都没有响应。</li><li>引发网络阻塞：每次获取大 key 产生的网络流量较大，如果一个 key 的大小是 1 MB，每秒访问量为 1000，那么每秒会产生 1000MB 的流量，这对于普通千兆网卡的服务器来说是灾难性的。</li><li>阻塞工作线程：如果使用 del 删除大 key 时，会阻塞工作线程，这样就没办法处理后续的命令。</li></ul><h3 id="查找大-key" tabindex="-1">查找大 key <a class="header-anchor" href="#查找大-key" aria-label="Permalink to &quot;查找大 key&quot;">​</a></h3><p>当我们在使用 Redis 自带的 <code>--bigkeys</code> 参数查找大 key 时，最好选择在从节点上执行该命令，因为主节点上执行时，会<strong>阻塞</strong>主节点。</p><ul><li><p>我们还可以使用 SCAN 命令来查找大 key；</p></li><li><p>通过分析 RDB 文件来找出 big key，这种方案的前提是 Redis 采用的是 RDB 持久化。网上有现成的工具：</p></li><li><ul><li>redis-rdb-tools：Python 语言写的用来分析 Redis 的 RDB 快照文件用的工具</li><li>rdb_bigkeys：Go 语言写的用来分析 Redis 的 RDB 快照文件用的工具，性能更好。</li></ul></li></ul><h2 id="删除大-key" tabindex="-1">删除大 key <a class="header-anchor" href="#删除大-key" aria-label="Permalink to &quot;删除大 key&quot;">​</a></h2><p>删除操作的本质是要释放键值对占用的内存空间。</p><p>释放内存只是第一步，为了更加高效地管理内存空间，在应用程序释放内存时，<strong>操作系统需要把释放掉的内存块插入一个空闲内存块的链表</strong>，以便后续进行管理和再分配。这个过程本身需要一定时间，而且会<strong>阻塞</strong>当前释放内存的应用程序。</p><p>所以，如果一下子释放了大量内存，空闲内存块链表操作时间就会增加，相应地就会造成 Redis <strong>主线程的阻塞</strong>，如果主线程发生了阻塞，其他所有请求可能都会超时，超时越来越多，会造成 Redis 连接耗尽，产生各种异常。</p><blockquote><p>删除大 key 时建议采用分批次删除和异步删除的方式进行。</p></blockquote><h2 id="清空数据库" tabindex="-1">清空数据库 <a class="header-anchor" href="#清空数据库" aria-label="Permalink to &quot;清空数据库&quot;">​</a></h2><p>清空数据库和上面 bigkey 删除也是同样道理，flushdb、flushall 也涉及到删除和释放所有的键值对，是 Redis 阻塞点</p><h2 id="集群扩容" tabindex="-1">集群扩容 <a class="header-anchor" href="#集群扩容" aria-label="Permalink to &quot;集群扩容&quot;">​</a></h2><p>Redis 集群可以进行节点的动态扩容缩容，这一过程目前还处于<strong>半自动</strong>状态，需要人工介入。</p><p>在扩缩容的时候，需要进行数据迁移。而 Redis 为了保证迁移的一致性，迁移所有操作都是<strong>同步</strong>操作。</p><p>执行迁移时，两端的 Redis 均会进入时长不等的<strong>阻塞</strong>状态，对于小Key，该时间可以忽略不计，但如果一旦 Key 的内存使用过大，严重的时候会触发集群内的故障转移，造成不必要的切换。</p><h1 id="java客户端" tabindex="-1">Java客户端 <a class="header-anchor" href="#java客户端" aria-label="Permalink to &quot;Java客户端&quot;">​</a></h1><p>在Redis官网中提供了各种语言的客户端，地址：<a href="https://redis.io/clients" target="_blank" rel="noreferrer">https://redis.io/clients</a></p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205042034494.png" alt="image-20220504203402416" style="zoom:80%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205042034563.png" alt="image-20220504203435492" style="zoom:67%;"><h1 id="jedis" tabindex="-1">Jedis <a class="header-anchor" href="#jedis" aria-label="Permalink to &quot;Jedis&quot;">​</a></h1><p>Jedis 是老牌Redis 的 Java 客户端，提供了比较全面的 Redis 命令的操作支持，是目前使用最广泛的客户端</p><p>官方：<a href="https://github.com/redis/jedis" target="_blank" rel="noreferrer">https://github.com/redis/jedis</a></p><p>文档：<a href="https://www.javadoc.io/doc/redis.clients/jedis/latest/index.html" target="_blank" rel="noreferrer">https://www.javadoc.io/doc/redis.clients/jedis/latest/index.html</a></p><blockquote><p>优点很突出：比较全面的提供了 Redis 的操作特性，也就是说你能用 redis 命令操作的，Jedis 包都也给你封装好了。使用广泛，易上手</p></blockquote><p>当然，缺点也有：</p><blockquote><ul><li>Jedis 客户端实例不是线程安全的，需要借助连接池来管理和使用 Jedis</li><li>使用阻塞的I/O，方法调用都是同步，程序流需要等到 sockets 处理完 I/O 才能执行，不支持异步</li></ul></blockquote><p>如何在项目中集成 Jedis 呢？请看下文！</p><h2 id="快速入门-1" tabindex="-1">快速入门 <a class="header-anchor" href="#快速入门-1" aria-label="Permalink to &quot;快速入门&quot;">​</a></h2><h3 id="引入依赖" tabindex="-1">引入依赖 <a class="header-anchor" href="#引入依赖" aria-label="Permalink to &quot;引入依赖&quot;">​</a></h3><p>功能：就是使用java来操作redis,创建maven工程，引入Jedis依赖</p><div class="language-xml"><button title="Copy Code" class="copy"></button><span class="lang">xml</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">redis.clients</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">jedis</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">version</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">4.3.1</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">version</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span></code></pre></div><h3 id="创建和关闭连接" tabindex="-1">创建和关闭连接 <a class="header-anchor" href="#创建和关闭连接" aria-label="Permalink to &quot;创建和关闭连接&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Jedis</span><span style="color:#A6ACCD;"> jedis</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">BeforeEach</span></span>
<span class="line"><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">setUp</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> throws Exception </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 1.构造一个 Jedis 对象，因为这里使用的默认端口 6379，所以不用配置端口</span></span>
<span class="line"><span style="color:#A6ACCD;">    jedis </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Jedis</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">192.168.88.101</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">6379</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 2.密码认证</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// jedis.auth(&quot;111111&quot;);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 3.测试是否连接成功</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> ping </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> jedis</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">ping</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 4.返回 pong 表示连接成功</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">ping</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">AfterEach</span></span>
<span class="line"><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">tearDown</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> throws Exception </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">jedis </span><span style="color:#89DDFF;">!=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">null)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        jedis</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">close</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="测试增删" tabindex="-1">测试增删 <a class="header-anchor" href="#测试增删" aria-label="Permalink to &quot;测试增删&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">setJedis</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 1.设置字符串</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> res </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> jedis</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">set</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">name</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">张三</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">res</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 2.获取字符串</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> name </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> jedis</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">get</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">name</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">name = </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;"> name</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202306151634049.png" alt="image-20230615163402974" style="zoom:80%;"><div class="language-JAVA"><button title="Copy Code" class="copy"></button><span class="lang">JAVA</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testHash</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    jedis</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">hset</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">user:1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">name</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">张三</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    jedis</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">hset</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">user:1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">age</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">33</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 获取所有的属性</span></span>
<span class="line"><span style="color:#A6ACCD;">    jedis</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">hgetAll</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">user:1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">forEach</span><span style="color:#89DDFF;">((</span><span style="color:#A6ACCD;">k</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> v</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">-&gt;</span><span style="color:#A6ACCD;"> System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">k </span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;"> = </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;"> v</span><span style="color:#89DDFF;">));</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202306151637156.png" alt="image-20230615163735080" style="zoom:80%;"><blockquote><p>对于 Jedis 而言，一旦连接上了 Redis 服务器，剩下的操作就非常容易了，<strong>由于 Jedis 中的 API 和 Redis 的命令高度一致，所以，Jedis 中的方法见名知意，直接使用即可</strong>。</p></blockquote><h2 id="连接池" tabindex="-1">连接池 <a class="header-anchor" href="#连接池" aria-label="Permalink to &quot;连接池&quot;">​</a></h2><blockquote><p>虽然 redis 服务端是单线程操作，但是在实际项目中，使用 Jedis 对象来操作 redis 时，每次操作都需要新建/关闭 TCP 连接，连接资源开销很高，同时 Jedis 对象的个数不受限制，在极端情况下可能会造成连接泄漏，同时 Jedis 存在多线程不安全的问题。</p></blockquote><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">JedisConnectionFactory</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">static</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">final</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">JedisPool</span><span style="color:#A6ACCD;"> jedisPool</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">static</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">JedisPoolConfig</span><span style="color:#A6ACCD;"> jedisPoolConfig </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">JedisPoolConfig</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 最大连接</span></span>
<span class="line"><span style="color:#A6ACCD;">        jedisPoolConfig</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setMaxTotal</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">8</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 最大空闲连接</span></span>
<span class="line"><span style="color:#A6ACCD;">        jedisPoolConfig</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setMaxIdle</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">8</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 最小空闲连接</span></span>
<span class="line"><span style="color:#A6ACCD;">        jedisPoolConfig</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setMinIdle</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">0</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 设置最长等待时间， ms</span></span>
<span class="line"><span style="color:#A6ACCD;">        jedisPoolConfig</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setMaxWait</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">Duration</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">ofMillis</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">200</span><span style="color:#89DDFF;">));</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 有密码就跟着写就行，没有就不设置</span></span>
<span class="line"><span style="color:#A6ACCD;">        jedisPool </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">JedisPool</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">jedisPoolConfig</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">192.168.88.101</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">6379</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span></span>
<span class="line"><span style="color:#A6ACCD;">                                  </span><span style="color:#F78C6C;">1000</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">315217</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 获取Jedis对象</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">static</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Jedis</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">getJedis</span><span style="color:#89DDFF;">(){</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> jedisPool</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getResource</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><blockquote><p>只需要修改下面的连接即可，其他不变</p></blockquote><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">BeforeEach</span></span>
<span class="line"><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">setUp</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> throws Exception </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 1.构造一个 Jedis 对象，因为这里使用的默认端口 6379，所以不用配置端口</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 修改这里使用连接池即可</span></span>
<span class="line"><span style="color:#A6ACCD;">    jedis </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> JedisConnectionFactory</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getJedis</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 2.密码认证</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// jedis.auth(&quot;111111&quot;);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 3.测试是否连接成功</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> ping </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> jedis</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">ping</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 4.返回 pong 表示连接成功</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">ping</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h2 id="验证码案例" tabindex="-1">验证码案例 <a class="header-anchor" href="#验证码案例" aria-label="Permalink to &quot;验证码案例&quot;">​</a></h2><blockquote><p>1、输入手机号，点击发送后随机生成6位数字码，2分钟有效</p><p>2、输入验证码，点击验证，返回成功或失败</p><p>3、每个手机号每天只能输入3次</p></blockquote><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20210917151726227.png" alt="image-20210917151726227"></p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">package</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">com</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">it</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">jedis</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F78C6C;">import</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">redis</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">clients</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">jedis</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">Jedis</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F78C6C;">import</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">java</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">util</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">Random</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">PhoneCode</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">static</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">main</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">[]</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">args</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">//模拟验证码发送</span></span>
<span class="line"><span style="color:#89DDFF;">		</span><span style="color:#676E95;font-style:italic;">//verifyCode(&quot;17315118674&quot;);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">Jedis</span><span style="color:#A6ACCD;"> jedis </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Jedis</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">127.0.0.1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">6379</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 获取正确的验证码</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> code </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> jedis</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">get</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">VerifyCode17315118674:code</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">code</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">//进行判断验证码正确性</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#82AAFF;">getRedisCode</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">17315118674</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">code</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//3、验证码校验</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">static</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">getRedisCode</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">phone</span><span style="color:#89DDFF;">,</span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">code</span><span style="color:#89DDFF;">){</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">//从redis获取验证码</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">Jedis</span><span style="color:#A6ACCD;"> jedis </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Jedis</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">127.0.0.1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">6379</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">//验证码key</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> codeKey </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">VerifyCode</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;">phone</span><span style="color:#89DDFF;">+</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">:code</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> redisCode </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> jedis</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">get</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">codeKey</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">//判断</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">redisCode</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">equals</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">code</span><span style="color:#89DDFF;">)){</span></span>
<span class="line"><span style="color:#A6ACCD;">            System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">成功</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span><span style="color:#89DDFF;font-style:italic;">else</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">            System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">失败</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#A6ACCD;">        jedis</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">close</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//2、每个手机号每天只能发三次，验证码放到redis中，设置过期时间</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">static</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">verifyCode</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">phone</span><span style="color:#89DDFF;">){</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">//连接redis</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">Jedis</span><span style="color:#A6ACCD;"> jedis </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Jedis</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">127.0.0.1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">6379</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">//拼接key</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">//手机发送次数key</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> countKey </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">VerifyCode</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;">phone</span><span style="color:#89DDFF;">+</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">:count</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">//验证码key</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> codeKey </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">VerifyCode</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;">phone</span><span style="color:#89DDFF;">+</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">:code</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">//每个手机只能发送三次</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> count </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> jedis</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">get</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">countKey</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">count </span><span style="color:#89DDFF;">==</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">null){</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">//没有发送次数，第一次发送</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">//设置发送次数是1</span></span>
<span class="line"><span style="color:#A6ACCD;">            jedis</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setex</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">countKey</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">24</span><span style="color:#89DDFF;">*</span><span style="color:#F78C6C;">60</span><span style="color:#89DDFF;">*</span><span style="color:#F78C6C;">60</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span><span style="color:#89DDFF;font-style:italic;">else</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">Integer</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">parseInt</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">count</span><span style="color:#89DDFF;">)&lt;=</span><span style="color:#F78C6C;">2</span><span style="color:#89DDFF;">){</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">//发送次数+1</span></span>
<span class="line"><span style="color:#A6ACCD;">            jedis</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">incr</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">countKey</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span><span style="color:#89DDFF;font-style:italic;">else</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">Integer</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">parseInt</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">count</span><span style="color:#89DDFF;">)&gt;</span><span style="color:#F78C6C;">2</span><span style="color:#89DDFF;">){</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">//发送三次，不能再发送</span></span>
<span class="line"><span style="color:#A6ACCD;">            System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">今天已经超过三次了</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">            jedis</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">close</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">//验证码放到redis里面</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> vcode </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">getCode</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">        jedis</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setex</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">codeKey</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">120</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">vcode</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        jedis</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">close</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//1、生成6位验证码</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">static</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">getCode</span><span style="color:#89DDFF;">(){</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">Random</span><span style="color:#A6ACCD;"> random </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">Random</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> code </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;&quot;</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">for</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">&lt;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">6</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;"> i</span><span style="color:#89DDFF;">++)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> rand </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> random</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">nextInt</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">10</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">            code </span><span style="color:#89DDFF;">+=</span><span style="color:#A6ACCD;"> rand</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> code</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h2 id="集群配置" tabindex="-1">集群配置 <a class="header-anchor" href="#集群配置" aria-label="Permalink to &quot;集群配置&quot;">​</a></h2><blockquote><p>在实际的项目生产环境中，redis 通常不是以单台服务实例来运行的，因为一旦服务器挂了，可能所有的下游服务都会受到影响，因此为了保障单台服务器即使出现故障也能运行，通常运维组会搭建集群环境，来保证服务高可用。</p></blockquote><p>搭建的方式有两种，哨兵模式和 Cluster 模式。</p><blockquote><ul><li>哨兵模式：对redis服务器进行监控，如果有宕机的，就从备机里面选一个出来作为主机</li><li>Cluster 模式：将数据进行分片存储，避免全部节点数据都一样，浪费空间</li></ul></blockquote><h3 id="哨兵模式" tabindex="-1">哨兵模式 <a class="header-anchor" href="#哨兵模式" aria-label="Permalink to &quot;哨兵模式&quot;">​</a></h3><p>哨兵模式简单的说，就是一台主机，一台备机，外加一台监控服务，当监控服务观测到主机已经宕机，就会将备用机切换成主机，以便继续提供服务。</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">RedisPoolUtils</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">static</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Jedis</span><span style="color:#A6ACCD;"> jedis</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">static</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">JedisSentinelPool</span><span style="color:#A6ACCD;"> jedisSentinelPool</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">static</span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">try</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#C792EA;">JedisPoolConfig</span><span style="color:#A6ACCD;"> config </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">JedisPoolConfig</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">//最大空闲连接数, 默认8个</span></span>
<span class="line"><span style="color:#A6ACCD;">            config</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setMaxIdle</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">8</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">//最大连接数, 默认8个</span></span>
<span class="line"><span style="color:#A6ACCD;">            config</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setMaxTotal</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">8</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">//最小空闲连接数, 默认0</span></span>
<span class="line"><span style="color:#A6ACCD;">            config</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setMinIdle</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">0</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">//获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">//如果超时就抛异常, 小于零:阻塞不确定的时间,  默认-1</span></span>
<span class="line"><span style="color:#A6ACCD;">            config</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setMaxWaitMillis</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">3000</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">//在获取连接的时候检查有效性,表示取出的redis对象可用, 默认false</span></span>
<span class="line"><span style="color:#A6ACCD;">            config</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setTestOnBorrow</span><span style="color:#89DDFF;">(true);</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">//redis服务器列表</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#C792EA;">Set</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> sentinels </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">HashSet</span><span style="color:#89DDFF;">&lt;&gt;();</span></span>
<span class="line"><span style="color:#A6ACCD;">            sentinels</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">add</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">HostAndPort</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">192.168.43.212</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">26379</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">toString</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#A6ACCD;">            sentinels</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">add</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">HostAndPort</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">192.168.43.213</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">26379</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">toString</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#A6ACCD;">            sentinels</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">add</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">HostAndPort</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">192.168.43.214</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">26379</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">toString</span><span style="color:#89DDFF;">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">//初始化连接池</span></span>
<span class="line"><span style="color:#A6ACCD;">            jedisSentinelPool </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">JedisSentinelPool</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">mymaster</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> sentinels</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span></span>
<span class="line"><span style="color:#A6ACCD;">                                                      config</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">111111</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">// 从池中获取一个Jedis对象</span></span>
<span class="line"><span style="color:#A6ACCD;">            jedis </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> jedisSentinelPool</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getResource</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">catch</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">Exception</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">e</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">            e</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">printStackTrace</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="集群模式" tabindex="-1">集群模式 <a class="header-anchor" href="#集群模式" aria-label="Permalink to &quot;集群模式&quot;">​</a></h3><p>为了保证高可用，redis-cluster集群通常会引入主从复制模型，一个主节点对应一个或者多个从节点，当主节点宕机的时候，就会启用从节点。</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">RedisPoolUtils</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">static</span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">try</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#C792EA;">JedisPoolConfig</span><span style="color:#A6ACCD;"> config </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">JedisPoolConfig</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">//最大空闲连接数, 默认8个</span></span>
<span class="line"><span style="color:#A6ACCD;">            config</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setMaxIdle</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">8</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">//最大连接数, 默认8个</span></span>
<span class="line"><span style="color:#A6ACCD;">            config</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setMaxTotal</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">8</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">//最小空闲连接数, 默认0</span></span>
<span class="line"><span style="color:#A6ACCD;">            config</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setMinIdle</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">0</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">//获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">//如果超时就抛异常, 小于零:阻塞不确定的时间,  默认-1</span></span>
<span class="line"><span style="color:#A6ACCD;">            config</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setMaxWaitMillis</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">3000</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">//在获取连接的时候检查有效性,表示取出的redis对象可用, 默认false</span></span>
<span class="line"><span style="color:#A6ACCD;">            config</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setTestOnBorrow</span><span style="color:#89DDFF;">(true);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#C792EA;">Set</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">HostAndPort</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> nodes </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">HashSet</span><span style="color:#89DDFF;">&lt;&gt;();</span></span>
<span class="line"><span style="color:#A6ACCD;">            nodes</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">add</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">HostAndPort</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">192.168.43.212</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">26379</span><span style="color:#89DDFF;">));</span></span>
<span class="line"><span style="color:#A6ACCD;">            nodes</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">add</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">HostAndPort</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">192.168.43.213</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">26379</span><span style="color:#89DDFF;">));</span></span>
<span class="line"><span style="color:#A6ACCD;">            nodes</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">add</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">HostAndPort</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">192.168.43.214</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">26379</span><span style="color:#89DDFF;">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#C792EA;">JedisCluster</span><span style="color:#A6ACCD;"> jedisCluster </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">JedisCluster</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">nodes</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> config</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">            jedisCluster</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">set</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">key</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">hello world</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">            jedisCluster</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">close</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">catch</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">Exception</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">e</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">            e</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">printStackTrace</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h1 id="springdataredis-⭐" tabindex="-1">SpringDataRedis ⭐ <a class="header-anchor" href="#springdataredis-⭐" aria-label="Permalink to &quot;SpringDataRedis ⭐&quot;">​</a></h1><blockquote><p>SpringData是Spring中数据操作的模块，包含对各种数据库的集成，其中对Redis的集成模块就叫做SpringDataRedis，官网地址：<a href="https://spring.io/projects/spring-data-redis" target="_blank" rel="noreferrer">https://spring.io/projects/spring-data-redis</a></p></blockquote><blockquote><ul><li><p>提供了对不同Redis客户端的整合（Lettuce和Jedis）</p></li><li><p>提供了RedisTemplate统一API来操作Redis</p></li><li><p>支持Redis的发布订阅模型</p></li><li><p>支持Redis哨兵和Redis集群</p></li><li><p>支持基于Lettuce的响应式编程</p></li><li><p>支持基于JDK、JSON、字符串、Spring对象的数据序列化及反序列化</p></li><li><p>支持基于Redis的JDKCollection实现</p></li></ul></blockquote><h2 id="快速入门-2" tabindex="-1">快速入门 <a class="header-anchor" href="#快速入门-2" aria-label="Permalink to &quot;快速入门&quot;">​</a></h2><p>SpringDataRedis中提供了RedisTemplate工具类，其中封装了各种对Redis的操作。并且将不同数据类型</p><p>的操作API封装到了不同的类型中：</p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220303172431308.png" alt="image-20220303172431308"></p><h3 id="引入依赖-1" tabindex="-1">引入依赖 <a class="header-anchor" href="#引入依赖-1" aria-label="Permalink to &quot;引入依赖&quot;">​</a></h3><div class="language-xml"><button title="Copy Code" class="copy"></button><span class="lang">xml</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">&lt;!--Redis依赖--&gt;</span></span>
<span class="line"><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">org.springframework.boot</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">spring-boot-starter-data-redis</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">&lt;!--连接池依赖--&gt;</span></span>
<span class="line"><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">org.apache.commons</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">commons-pool2</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span></code></pre></div><h3 id="配置文件" tabindex="-1">配置文件 <a class="header-anchor" href="#配置文件" aria-label="Permalink to &quot;配置文件&quot;">​</a></h3><div class="language-yml"><button title="Copy Code" class="copy"></button><span class="lang">yml</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F07178;">spring</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F07178;">redis</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">     </span><span style="color:#F07178;">port</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">6379</span></span>
<span class="line"><span style="color:#A6ACCD;">     </span><span style="color:#F07178;">host</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">192.168.88.101</span></span>
<span class="line"><span style="color:#A6ACCD;">     </span><span style="color:#F07178;">database</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;">#操作的是0号数据库</span></span>
<span class="line"><span style="color:#A6ACCD;">     </span><span style="color:#F07178;">password</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">315217</span></span>
<span class="line"><span style="color:#A6ACCD;">     </span><span style="color:#F07178;">lettuce</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;"># 默认连接池，不写不生效</span></span>
<span class="line"><span style="color:#A6ACCD;">       </span><span style="color:#F07178;">pool</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">         </span><span style="color:#F07178;">max-active</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">8</span><span style="color:#A6ACCD;">  </span><span style="color:#676E95;font-style:italic;"># 最大连接（使用负值表示没有限制）</span></span>
<span class="line"><span style="color:#A6ACCD;">         </span><span style="color:#F07178;">max-idle</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">8</span><span style="color:#A6ACCD;">    </span><span style="color:#676E95;font-style:italic;"># 最大空闲连接</span></span>
<span class="line"><span style="color:#A6ACCD;">         </span><span style="color:#F07178;">min-idle</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#A6ACCD;">    </span><span style="color:#676E95;font-style:italic;"># 最小空闲连接</span></span>
<span class="line"><span style="color:#A6ACCD;">         </span><span style="color:#F07178;">max-wait</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">100ms</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;"># 连接等待时间(负数表示没限制)</span></span>
<span class="line"><span style="color:#A6ACCD;">         </span><span style="color:#F07178;">time-between-eviction-runs</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">10s</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;">#每10s运行一次空闲连接回收器(独立线程)</span></span></code></pre></div><h3 id="注入测试" tabindex="-1">注入测试 <a class="header-anchor" href="#注入测试" aria-label="Permalink to &quot;注入测试&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">SpringBootTest</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">RedisTest</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Resource</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">RedisTemplate</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Object</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testString</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 插入一条string类型数据</span></span>
<span class="line"><span style="color:#A6ACCD;">        redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForValue</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">set</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">name</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">李四</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 读取一条string类型数据</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">Object</span><span style="color:#A6ACCD;"> name </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForValue</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">get</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">name</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">name = </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;"> name</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202306152115431.png" alt="image-20230615211552308" style="zoom:80%;"><h2 id="序列化" tabindex="-1">序列化 <a class="header-anchor" href="#序列化" aria-label="Permalink to &quot;序列化&quot;">​</a></h2><h3 id="为什么序列化" tabindex="-1">为什么序列化 <a class="header-anchor" href="#为什么序列化" aria-label="Permalink to &quot;为什么序列化&quot;">​</a></h3><blockquote><p>RedisTemplate可以接收任意Object作为值写入Redis，只不过写入前会把Object序列化为字节形式，默认是采用JDK序列化，得到的结果是这样的：</p></blockquote><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220303173049972.png" alt="image-20220303173049972"></p><blockquote><p>缺点：可读性差、内存占用较大、最重要的是无法直接读取</p></blockquote><h3 id="自动序列化" tabindex="-1">自动序列化 <a class="header-anchor" href="#自动序列化" aria-label="Permalink to &quot;自动序列化&quot;">​</a></h3><blockquote><p>我们可以自定义RedisTemplate的序列化方式，代码如下：</p></blockquote><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Configuration</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">RedisConfig</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Bean</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">RedisTemplate</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">,</span><span style="color:#C792EA;">Object</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">redisTemplate</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">LettuceConnectionFactory</span></span>
<span class="line"><span style="color:#A6ACCD;">                                                      </span><span style="color:#A6ACCD;font-style:italic;">lettuceConnectionFactory</span><span style="color:#89DDFF;">){</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 创建redisTemplate</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">RedisTemplate</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">,</span><span style="color:#C792EA;">Object</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> redisTemplate </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">RedisTemplate</span><span style="color:#89DDFF;">&lt;&gt;();</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">// 设置连接工厂</span></span>
<span class="line"><span style="color:#A6ACCD;">        redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setConnectionFactory</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">lettuceConnectionFactory</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">//设置key序列化方式string</span></span>
<span class="line"><span style="color:#A6ACCD;">        redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setKeySerializer</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">StringRedisSerializer</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">//设置value的序列化方式json</span></span>
<span class="line"><span style="color:#A6ACCD;">        redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setValueSerializer</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">GenericJackson2JsonRedisSerializer</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#A6ACCD;">        redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setHashKeySerializer</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">StringRedisSerializer</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#A6ACCD;">        redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setHashValueSerializer</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;font-style:italic;">new</span></span>
<span class="line"><span style="color:#A6ACCD;">                </span><span style="color:#82AAFF;">GenericJackson2JsonRedisSerializer</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#A6ACCD;">        redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">afterPropertiesSet</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><blockquote><p>序列号完成后，进行测试，保存数据(对象类型)</p></blockquote><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Override</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Boolean</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">save</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">admin admin</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//1 先插入mysql并成功</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> adminMapper</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">insert</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">admin</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">i </span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">//2 需要再次查询一下mysql将数据捞回来并ok</span></span>
<span class="line"><span style="color:#A6ACCD;">        admin </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> adminMapper</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">selectById</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">admin</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getId</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">//3 将捞出来的user存进redis，完成新增功能的数据一致性。</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> key </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> CACHE_KEY_USER</span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;">admin</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getId</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">        redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForValue</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">set</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">key</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">admin</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 插入删除等操作返回的都是影响行数，即是数字。那么则大于0为真，其他情况为假</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">true;</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><blockquote><p>查询数据(对象)</p></blockquote><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Override</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> admin </span><span style="color:#82AAFF;">getById</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">Integer</span><span style="color:#A6ACCD;"> id</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    admin ad </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">null;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> key </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> CACHE_KEY_USER</span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;">id</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//1 先从redis里面查询，如果有直接返回结果，如果没有再去查询mysql</span></span>
<span class="line"><span style="color:#A6ACCD;">    ad  </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">admin</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForValue</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">get</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">key</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">ad</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">ad </span><span style="color:#89DDFF;">==</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">null){</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">//2 redis里面无，继续查询mysql</span></span>
<span class="line"><span style="color:#A6ACCD;">        ad </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> adminMapper</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">selectById</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">id</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">ad </span><span style="color:#89DDFF;">==</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">null){</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">//3.1 redis+mysql 都无数据</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">//你具体细化，防止多次穿透，我们规定，记录下导致穿透的这个key回写redis</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> ad</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span><span style="color:#89DDFF;font-style:italic;">else</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">//3.2 mysql有，需要将数据写回redis，保证下一次的缓存命中率</span></span>
<span class="line"><span style="color:#A6ACCD;">            redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForValue</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">set</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">key</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">ad</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> ad</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220303182031944.png" alt="image-20220303182031944" style="zoom:67%;"><blockquote><p>查询所有</p></blockquote><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Override</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">List</span><span style="color:#89DDFF;">&lt;</span><span style="color:#A6ACCD;">admin</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">getAll</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">List</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">admin</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> admins </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">null;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">List</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">admin</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> all </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">List</span><span style="color:#89DDFF;">&lt;</span><span style="color:#A6ACCD;">admin</span><span style="color:#89DDFF;">&gt;)</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForValue</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">get</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">all</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">all </span><span style="color:#89DDFF;">==</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">null){</span></span>
<span class="line"><span style="color:#A6ACCD;">        admins </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> adminMapper</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">selectList</span><span style="color:#89DDFF;">(null);</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">admins </span><span style="color:#89DDFF;">==</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">null)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">null;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span><span style="color:#89DDFF;font-style:italic;">else</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">            redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForValue</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">set</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">all</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">admins</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> admins</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220303181631969.png" alt="image-20220303181631969" style="zoom:50%;"><blockquote><p>尽管JSON的序列化方式可以满足我们的需求，但依然存在一些问题，如图：</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220303183028063.png" alt="image-20220303183028063" style="zoom:67%;"><blockquote><p>为了在反序列化时知道对象的类型，<code>JSON序列化器会将类的class类型写入json结果中</code>，存入Redis，会带来额外的内存开销。</p></blockquote><h3 id="手动序列化⭐" tabindex="-1">手动序列化⭐ <a class="header-anchor" href="#手动序列化⭐" aria-label="Permalink to &quot;手动序列化⭐&quot;">​</a></h3><blockquote><p>为了节省内存空间，我们并不会使用JSON序列化器来处理value，而是统一使用String序列化器，要求只能存储String类型的key和value。当需要存储Java对象时，手动完成对象的序列化和反序列化。</p></blockquote><blockquote><p><code>这样就不用上面的配置类了，但是写序列化和反序列化稍烦</code></p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220303183201118.png" alt="image-20220303183201118" style="zoom:80%;"><blockquote><p>Spring默认提供了一个<strong>StringRedisTemplate</strong>类，它的key和value的序列化方式默认就是String方式。省去了我们自定义RedisTemplate的过程</p></blockquote><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Resource</span></span>
<span class="line"><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">StringRedisTemplate</span><span style="color:#A6ACCD;"> stringRedisTemplate</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">//JSON工具</span></span>
<span class="line"><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">static</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">final</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">ObjectMapper</span><span style="color:#A6ACCD;"> mapper </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">ObjectMapper</span><span style="color:#89DDFF;">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testString2</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> throws JsonProcessingException </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 准备对象</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">User</span><span style="color:#A6ACCD;"> user </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">User</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">任硕</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">18</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 手动转换为json</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> json </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> mapper</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">writeValueAsString</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">user</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 插入一条string类型数据</span></span>
<span class="line"><span style="color:#A6ACCD;">    stringRedisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForValue</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">set</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">user:200</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> json</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 读取一条string类型数据</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> val </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> stringRedisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForValue</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">get</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">user:200</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 反序列化</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">User</span><span style="color:#A6ACCD;"> user1 </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> mapper</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">readValue</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">val</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> User</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">class</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">user1 = </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;"> user1</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202306152130724.png" alt="image-20230615213040665" style="zoom:80%;"><h3 id="序列化cache方法" tabindex="-1">序列化Cache方法 <a class="header-anchor" href="#序列化cache方法" aria-label="Permalink to &quot;序列化Cache方法&quot;">​</a></h3><blockquote><p>就是使用@Cache注解方式来实现缓存操作的</p></blockquote><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Bean</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">CacheManager</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">cacheManager</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">RedisConnectionFactory</span><span style="color:#A6ACCD;"> factory</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 解决查询缓存转换异常的问题</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">ObjectMapper</span><span style="color:#A6ACCD;"> om </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">ObjectMapper</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//POJO无public的属性或方法时，不报错</span></span>
<span class="line"><span style="color:#A6ACCD;">    om</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">disable</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">SerializationFeature</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">FAIL_ON_EMPTY_BEANS</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// null值字段不显示</span></span>
<span class="line"><span style="color:#A6ACCD;">    om</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setSerializationInclusion</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">JsonInclude</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">Include</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">NON_NULL</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    om</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setVisibility</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">PropertyAccessor</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">ALL</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> JsonAutoDetect</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">Visibility</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">ANY</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 序列化JSON串时，在值上打印出对象类型</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 替换上方 过期的enableDefaultTyping</span></span>
<span class="line"><span style="color:#A6ACCD;">    om</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">activateDefaultTyping</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">LaissezFaireSubTypeValidator</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">instance </span><span style="color:#89DDFF;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">                             ObjectMapper</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">DefaultTyping</span></span>
<span class="line"><span style="color:#A6ACCD;">                             </span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">NON_FINAL</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> JsonTypeInfo</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">As</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">WRAPPER_ARRAY</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Jackson2JsonRedisSerializer</span><span style="color:#89DDFF;">&lt;&gt;(</span><span style="color:#A6ACCD;">Object</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">class</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">setObjectMapper</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">om</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 解决jackson2无法反序列化LocalDateTime的问题</span></span>
<span class="line"><span style="color:#A6ACCD;">    om</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">disable</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">SerializationFeature</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">WRITE_DATES_AS_TIMESTAMPS</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    om</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">registerModule</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">GeoModule</span><span style="color:#89DDFF;">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">// 配置序列化（解决乱码的问题）</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">RedisCacheConfiguration</span><span style="color:#A6ACCD;"> config </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> RedisCacheConfiguration</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">defaultCacheConfig</span><span style="color:#89DDFF;">()</span></span>
<span class="line"><span style="color:#89DDFF;">            </span><span style="color:#676E95;font-style:italic;">// 默认 30天过期</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">entryTtl</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">Duration</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">ofDays</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">30</span><span style="color:#89DDFF;">))</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">serializeKeysWith</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">RedisSerializationContext</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">SerializationPair</span></span>
<span class="line"><span style="color:#A6ACCD;">                               </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">fromSerializer</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">StringRedisSerializer</span><span style="color:#89DDFF;">()))</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">serializeValuesWith</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">RedisSerializationContext</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">SerializationPair</span></span>
<span class="line"><span style="color:#A6ACCD;">                                 </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">fromSerializer</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span></span>
<span class="line"><span style="color:#A6ACCD;">                                                 </span><span style="color:#82AAFF;">GenericJackson2JsonRedisSerializer</span><span style="color:#89DDFF;">()))</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">disableCachingNullValues</span><span style="color:#89DDFF;">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> RedisCacheManager</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">builder</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">factory</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">cacheDefaults</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">config</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">build</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h2 id="通用操作" tabindex="-1">通用操作 <a class="header-anchor" href="#通用操作" aria-label="Permalink to &quot;通用操作&quot;">​</a></h2><h3 id="获取所有key-判断value类型" tabindex="-1">获取所有key|判断value类型 <a class="header-anchor" href="#获取所有key-判断value类型" aria-label="Permalink to &quot;获取所有key|判断value类型&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">/**</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"> * 通用操作，针对不同的数据类型都可以操作</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">*/</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testCommon</span><span style="color:#89DDFF;">(){</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//获取Redis中所有的key</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Set</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> keys </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">keys</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">*</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">for</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> key </span><span style="color:#89DDFF;font-style:italic;">:</span><span style="color:#A6ACCD;"> keys</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">key</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//判断某个key是否存在</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Boolean</span><span style="color:#A6ACCD;"> itcast </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">hasKey</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">itcast</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">itcast</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//删除指定key</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">delete</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">myZset</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//获取指定key对应的value的数据类型</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">DataType</span><span style="color:#A6ACCD;"> dataType </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">type</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">myset</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">dataType</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">name</span><span style="color:#89DDFF;">());</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><p>这些方法在以下这几种类型中是通用的</p><p>提前注入RedisTemplate</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Autowired</span></span>
<span class="line"><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">RedisTemplate</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Object</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">;</span></span></code></pre></div><h3 id="删除单个key" tabindex="-1">删除单个key <a class="header-anchor" href="#删除单个key" aria-label="Permalink to &quot;删除单个key&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">//删除key</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">delete</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> key</span><span style="color:#89DDFF;">){</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">delete</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">key</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">//进行使用</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">//进行删除key</span></span>
<span class="line"><span style="color:#A6ACCD;">redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">delete</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">name</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span></code></pre></div><h3 id="删除多个key" tabindex="-1">删除多个key <a class="header-anchor" href="#删除多个key" aria-label="Permalink to &quot;删除多个key&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">//删除多个key</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">deleteKey</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">...</span><span style="color:#A6ACCD;">keys</span><span style="color:#89DDFF;">){</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">delete</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">keys</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">//进行使用</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">//删除多个key，传入的是集合元素</span></span>
<span class="line"><span style="color:#A6ACCD;">redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">delete</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">Arrays</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">asList</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">name1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">name2</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">));</span></span></code></pre></div><h3 id="指定key的失效时间" tabindex="-1">指定key的失效时间 <a class="header-anchor" href="#指定key的失效时间" aria-label="Permalink to &quot;指定key的失效时间&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">//指定key的失效时间</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">expire</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> key</span><span style="color:#89DDFF;">,</span><span style="color:#C792EA;">long</span><span style="color:#A6ACCD;"> time</span><span style="color:#89DDFF;">){</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">expire</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">key</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">time</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">MINUTES</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">//进行使用</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">//设置过期时间,25秒</span></span>
<span class="line"><span style="color:#A6ACCD;">redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">boundValueOps</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">id</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">set</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">2</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">25</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">SECONDS</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">//4、单独设置过期时间</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">//注意：值前面已经设置过了</span></span>
<span class="line"><span style="color:#A6ACCD;">redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">boundValueOps</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">name</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">expire</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">10</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">MINUTES</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">expire</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">name1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">10</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">MINUTES</span><span style="color:#89DDFF;">);</span></span></code></pre></div><h3 id="根据key获取过期时间" tabindex="-1">根据key获取过期时间 <a class="header-anchor" href="#根据key获取过期时间" aria-label="Permalink to &quot;根据key获取过期时间&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">//根据key获取过期时间</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">long</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">getExpire</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> key</span><span style="color:#89DDFF;">){</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> expire </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getExpire</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">key</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> expire</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">//进行使用</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">//获取过期时间,-2表示永久过期，否则显示剩余秒数</span></span>
<span class="line"><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> t </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getExpire</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">name</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">t</span><span style="color:#89DDFF;">);</span></span></code></pre></div><h3 id="判断key是否存在" tabindex="-1">判断key是否存在 <a class="header-anchor" href="#判断key是否存在" aria-label="Permalink to &quot;判断key是否存在&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">//判断key是否存在</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">boolean</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">hasKey</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> key</span><span style="color:#89DDFF;">){</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">hasKey</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">key</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">//进行使用</span></span>
<span class="line"><span style="color:#C792EA;">Boolean</span><span style="color:#A6ACCD;"> zSetKey1 </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">hasKey</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">zSetKey</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">zSetKey1</span><span style="color:#89DDFF;">);</span></span></code></pre></div><h2 id="准备数据" tabindex="-1">准备数据 <a class="header-anchor" href="#准备数据" aria-label="Permalink to &quot;准备数据&quot;">​</a></h2><h3 id="依赖" tabindex="-1">依赖 <a class="header-anchor" href="#依赖" aria-label="Permalink to &quot;依赖&quot;">​</a></h3><div class="language-xml"><button title="Copy Code" class="copy"></button><span class="lang">xml</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependencies</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">org.springframework.boot</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">spring-boot-starter-data-redis</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">com.baomidou</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">mybatis-plus-boot-starter</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">version</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">3.4.3</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">version</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">mysql</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">mysql-connector-java</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">version</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">5.1.47</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">version</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">org.apache.commons</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">commons-pool2</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">org.projectlombok</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">lombok</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">optional</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">true</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">optional</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependencies</span><span style="color:#89DDFF;">&gt;</span></span></code></pre></div><h3 id="application-yml" tabindex="-1">application.yml <a class="header-anchor" href="#application-yml" aria-label="Permalink to &quot;application.yml&quot;">​</a></h3><div class="language-yml"><button title="Copy Code" class="copy"></button><span class="lang">yml</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F07178;">spring</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F07178;">datasource</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F07178;">driver-class-name</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">com.mysql.jdbc.Driver</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F07178;">url</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">jdbc:mysql://127.0.0.1:3306/hmdp?useSSL=false&amp;serverTimezone=UTC</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F07178;">username</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">root</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F07178;">password</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">123456</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F07178;">redis</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F07178;">port</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">6379</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F07178;">host</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">127.0.0.1</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F07178;">lettuce</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;"># 默认连接池，不写不生效</span></span>
<span class="line"><span style="color:#A6ACCD;">      </span><span style="color:#F07178;">pool</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#F07178;">max-active</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">8</span><span style="color:#A6ACCD;">  </span><span style="color:#676E95;font-style:italic;"># 最大连接</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#F07178;">max-idle</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">8</span><span style="color:#A6ACCD;">    </span><span style="color:#676E95;font-style:italic;"># 最大空闲连接</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#F07178;">min-idle</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#A6ACCD;">    </span><span style="color:#676E95;font-style:italic;"># 最小空闲连接</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#F07178;">max-wait</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">100ms</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;"># 连接等待时间</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#F07178;">time-between-eviction-runs</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">10s</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;">#每10s运行一次空闲连接回收器(独立线程)</span></span></code></pre></div><h3 id="实体类" tabindex="-1">实体类 <a class="header-anchor" href="#实体类" aria-label="Permalink to &quot;实体类&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Data</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">boys</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> id</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">TableField</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">boyName</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> boyName</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">TableField</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">userCP</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> userCP</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> sex</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="mapper-1" tabindex="-1">mapper <a class="header-anchor" href="#mapper-1" aria-label="Permalink to &quot;mapper&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Mapper</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">interface</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">boysMapper</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">extends</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">BaseMapper</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">boys</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="序列化-1" tabindex="-1">序列化 <a class="header-anchor" href="#序列化-1" aria-label="Permalink to &quot;序列化&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Bean</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">RedisTemplate</span><span style="color:#89DDFF;">&lt;</span><span style="color:#A6ACCD;">String</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">Object</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">redisTemplate</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">LettuceConnectionFactory</span><span style="color:#A6ACCD;"> lettuceConnectionFactory</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">RedisTemplate</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">,</span><span style="color:#C792EA;">Object</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> redisTemplate </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">RedisTemplate</span><span style="color:#89DDFF;">&lt;&gt;();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setConnectionFactory</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">lettuceConnectionFactory</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//设置key序列化方式string</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setKeySerializer</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">StringRedisSerializer</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//设置value的序列化方式json</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setValueSerializer</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">GenericJackson2JsonRedisSerializer</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setHashKeySerializer</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">StringRedisSerializer</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setHashValueSerializer</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;font-style:italic;">new</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#82AAFF;">GenericJackson2JsonRedisSerializer</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">afterPropertiesSet</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="查询测试" tabindex="-1">查询测试 <a class="header-anchor" href="#查询测试" aria-label="Permalink to &quot;查询测试&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Resource</span></span>
<span class="line"><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">RedisTemplate</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Object</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Resource</span></span>
<span class="line"><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> boysMapper boysMapper</span><span style="color:#89DDFF;">;</span></span></code></pre></div><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">test</span><span style="color:#89DDFF;">(){</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">List</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">boys</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> list </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> boysMapper</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">selectList</span><span style="color:#89DDFF;">(null);</span></span>
<span class="line"><span style="color:#A6ACCD;">    list</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">forEach</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;font-style:italic;">::</span><span style="color:#A6ACCD;">println</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205080952770.png" alt="image-20220508095226714" style="zoom:80%;"><h2 id="string类型" tabindex="-1">String类型 <a class="header-anchor" href="#string类型" aria-label="Permalink to &quot;String类型&quot;">​</a></h2><h3 id="存储值" tabindex="-1">存储值 <a class="header-anchor" href="#存储值" aria-label="Permalink to &quot;存储值&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">/**</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"> * 操作String类型数据</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">*/</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testString</span><span style="color:#89DDFF;">(){</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//存值</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForValue</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">set</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">city123</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">beijing</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//取值</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> value </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">String</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForValue</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">get</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">city123</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">value</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//存值，同时设置过期时间</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForValue</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">set</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">key1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">value1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">10l</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">SECONDS</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//存值，如果存在则不执行任何操作</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Boolean</span><span style="color:#A6ACCD;"> aBoolean </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForValue</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">setIfAbsent</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">city1234</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">nanjing</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">aBoolean</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><p>使用手动序列化存储数据库字段</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">//注意：是StringRedisTemplate</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Resource</span></span>
<span class="line"><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">StringRedisTemplate</span><span style="color:#A6ACCD;"> stringRedisTemplate</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">//手动序列化</span></span>
<span class="line"><span style="color:#C792EA;">final</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">ObjectMapper</span><span style="color:#A6ACCD;">  mapper </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">ObjectMapper</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">//数据库查询</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Resource</span></span>
<span class="line"><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> boysMapper boysMapper</span><span style="color:#89DDFF;">;</span></span></code></pre></div><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">setBoys</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    boys list </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> boysMapper</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">selectById</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">2</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">try</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> s </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> mapper</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">writeValueAsString</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">list</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        stringRedisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForValue</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">set</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">hmdp:boys:2</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">s</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">catch</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">JsonProcessingException</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">e</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        e</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">printStackTrace</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205072115826.png" alt="image-20220507211551757" style="zoom:80%;"><p>加上过期时间</p><p>10s后过期</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">stringRedisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">opsForValue</span><span style="color:#89DDFF;">().</span><span style="color:#A6ACCD;">set</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">hmdp:boys:2</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">s</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">10</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">SECONDS</span><span style="color:#89DDFF;">);</span></span></code></pre></div><p>使用自定序列化(必须加载那个序列化bean，不然存入的全是二进制)</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">setBoys1</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    boys list </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> boysMapper</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">selectById</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">2</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForValue</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">set</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">hmdp:boys:2</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">list</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205072122374.png" alt="image-20220507212218312" style="zoom:80%;"><p>加上过期时间</p><p>10s后过期</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForValue</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">set</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">hmdp:boys:2</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">list</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">10</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">SECONDS</span><span style="color:#89DDFF;">);</span></span></code></pre></div><h3 id="获取值" tabindex="-1">获取值 <a class="header-anchor" href="#获取值" aria-label="Permalink to &quot;获取值&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">getOne</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Object</span><span style="color:#A6ACCD;"> b1 </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForValue</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">get</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">hmdp:boys:2</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">b1</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">boys</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">id</span><span style="color:#89DDFF;">=</span><span style="color:#F78C6C;">2</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> boyName</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">张飞</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> userCP</span><span style="color:#89DDFF;">=</span><span style="color:#F78C6C;">10</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> sex</span><span style="color:#89DDFF;">=</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">)</span></span></code></pre></div><h3 id="更新值" tabindex="-1">更新值 <a class="header-anchor" href="#更新值" aria-label="Permalink to &quot;更新值&quot;">​</a></h3><p>其实就是再次存储即可</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">UpdateOne</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    boys b1 </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">boys</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    b1</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setBoyName</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">张三</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    b1</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setUserCP</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">12</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    b1</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">setSex</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//存入Redis</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForValue</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">set</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">hmdp:boys:2</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">b1</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Object</span><span style="color:#A6ACCD;"> b </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForValue</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">get</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">hmdp:boys:2</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//存入数据库</span></span>
<span class="line"><span style="color:#A6ACCD;">    boysMapper</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">insert</span><span style="color:#89DDFF;">((</span><span style="color:#A6ACCD;">boys</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> b</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="其他方法测试" tabindex="-1">其他方法测试 <a class="header-anchor" href="#其他方法测试" aria-label="Permalink to &quot;其他方法测试&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">TestString</span><span style="color:#89DDFF;">(){</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//获取过期时间,-2表示永久过期，否则显示剩余秒数</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> t </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getExpire</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">hmdp:boys:2</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">t</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//进行删除key</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">delete</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">hmdp:boys:2</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//删除多个key，传入的是集合元素</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">delete</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">Arrays</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">asList</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">hmdp:boys:2</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">hmdp:boys:2</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//判断key是否存在</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Boolean</span><span style="color:#A6ACCD;"> b </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">hasKey</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">hmdp:boys:2</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">b</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h2 id="hash类型" tabindex="-1">Hash类型 <a class="header-anchor" href="#hash类型" aria-label="Permalink to &quot;Hash类型&quot;">​</a></h2><h3 id="存储值-1" tabindex="-1">存储值 <a class="header-anchor" href="#存储值-1" aria-label="Permalink to &quot;存储值&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">/**</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"> * 操作Hash类型数据</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">*/</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testHash</span><span style="color:#89DDFF;">(){</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">HashOperations</span><span style="color:#A6ACCD;"> hashOperations </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForHash</span><span style="color:#89DDFF;">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//存值</span></span>
<span class="line"><span style="color:#A6ACCD;">    hashOperations</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">put</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">002</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">name</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">xiaoming</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    hashOperations</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">put</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">002</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">age</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">20</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    hashOperations</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">put</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">002</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">address</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">bj</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//取值</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> age </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">String</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> hashOperations</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">get</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">002</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">age</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">age</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//获得hash结构中的所有字段</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Set</span><span style="color:#A6ACCD;"> keys </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> hashOperations</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">keys</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">002</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">for</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">Object</span><span style="color:#A6ACCD;"> key </span><span style="color:#89DDFF;font-style:italic;">:</span><span style="color:#A6ACCD;"> keys</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">key</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//获得hash结构中的所有值</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">List</span><span style="color:#A6ACCD;"> values </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> hashOperations</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">values</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">002</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">for</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">Object</span><span style="color:#A6ACCD;"> value </span><span style="color:#89DDFF;font-style:italic;">:</span><span style="color:#A6ACCD;"> values</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">value</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h4 id="存储普通值" tabindex="-1">存储普通值 <a class="header-anchor" href="#存储普通值" aria-label="Permalink to &quot;存储普通值&quot;">​</a></h4><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">setHash</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForHash</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">put</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">map</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">name</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">任硕</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForHash</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">put</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">map</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">age</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">12</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205072131990.png" alt="image-20220507213118927" style="zoom:80%;"><h4 id="存储map-常用" tabindex="-1">存储map(常用) <a class="header-anchor" href="#存储map-常用" aria-label="Permalink to &quot;存储map(常用)&quot;">​</a></h4><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">setHash1</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//通过Map插入值</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">HashMap</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Object</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> map </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">HashMap</span><span style="color:#89DDFF;">&lt;&gt;();</span></span>
<span class="line"><span style="color:#A6ACCD;">    map</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">put</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">name</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">张三</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    map</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">put</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">password</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">123456</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//加入对象，这和插入数据库对象一样</span></span>
<span class="line"><span style="color:#A6ACCD;">    boys b </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> boysMapper</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">selectById</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">2</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    map</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">put</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">hmdp:boys:2</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">b</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForHash</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">putAll</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">map2</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">map</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//设置过期时间(可选)</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">expire</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">map2</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">20</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">SECONDS</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205072137216.png" alt="image-20220507213738151" style="zoom:80%;"><h3 id="获取key" tabindex="-1">获取key <a class="header-anchor" href="#获取key" aria-label="Permalink to &quot;获取key&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">getHashKey</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//获取所有的key</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//1、通过redisTemplate获取值</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Set</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Object</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> keys1 </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">boundHashOps</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">HashKey</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">keys</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">keys1</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//2、通过ValueOperations获取值</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Set</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Object</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> keys2 </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForHash</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">keys</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">User</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">keys2</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="获取value" tabindex="-1">获取value <a class="header-anchor" href="#获取value" aria-label="Permalink to &quot;获取value&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">getHashValue</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//获取所有的value</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//1、通过redisTemplate获取值</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">List</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Object</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> values1 </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">boundHashOps</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">HashKey</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">values</span><span style="color:#89DDFF;">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//2、通过ValueOperations获取值</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">List</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Object</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> value2 </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForHash</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">values</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">User</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">values1</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">value2</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="根据key获取value" tabindex="-1">根据key获取value <a class="header-anchor" href="#根据key获取value" aria-label="Permalink to &quot;根据key获取value&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">getHashKeyValue</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//1、通过redisTemplate获取</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Object</span><span style="color:#A6ACCD;"> o </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">boundHashOps</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">HashKey</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">get</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">SmallKey1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">o</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//2、通过ValueOperations获取值</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Object</span><span style="color:#A6ACCD;"> o1 </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForHash</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">get</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">User</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">name</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">o1</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="获取所有的键值对集合" tabindex="-1">获取所有的键值对集合 <a class="header-anchor" href="#获取所有的键值对集合" aria-label="Permalink to &quot;获取所有的键值对集合&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">//获取所有键值对集合</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">getHashKeyAndValue</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//1、通过redisTemplate获取</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Map</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Object</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Object</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> entries </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">boundHashOps</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">HashKey</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">).</span><span style="color:#82AAFF;">entries</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//2、通过ValueOperations获取值</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Map</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Object</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">Object</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> entries1  </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForHash</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">entries</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">User</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">entries</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">entries1</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="删除等相关方法" tabindex="-1">删除等相关方法 <a class="header-anchor" href="#删除等相关方法" aria-label="Permalink to &quot;删除等相关方法&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testDeleteHash</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//删除小key</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForHash</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">delete</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">HashKey</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">SmallKey1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//删除大key</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">delete</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">HashKey</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Boolean</span><span style="color:#A6ACCD;"> b1 </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForHash</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">hasKey</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">HashKey</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">SmallKey2</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">b1</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//判断大key是否存在</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Boolean</span><span style="color:#A6ACCD;"> b2 </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">hasKey</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">HashKey</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">b2</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//获取过期时间</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> t </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getExpire</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">HashKey</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">t</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220304165150702.png" alt="image-20220304165150702" style="zoom:67%;"><h2 id="set类型" tabindex="-1">Set类型 <a class="header-anchor" href="#set类型" aria-label="Permalink to &quot;Set类型&quot;">​</a></h2><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">/**</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"> * 操作Set类型的数据</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">*/</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testSet</span><span style="color:#89DDFF;">(){</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">SetOperations</span><span style="color:#A6ACCD;"> setOperations </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForSet</span><span style="color:#89DDFF;">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//存值</span></span>
<span class="line"><span style="color:#A6ACCD;">    setOperations</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">add</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">myset</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">a</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">b</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">c</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">a</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//取值</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Set</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> myset </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> setOperations</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">members</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">myset</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">for</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> o </span><span style="color:#89DDFF;font-style:italic;">:</span><span style="color:#A6ACCD;"> myset</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">o</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//删除成员</span></span>
<span class="line"><span style="color:#A6ACCD;">    setOperations</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">remove</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">myset</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">a</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">b</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//取值</span></span>
<span class="line"><span style="color:#A6ACCD;">    myset </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> setOperations</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">members</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">myset</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">for</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> o </span><span style="color:#89DDFF;font-style:italic;">:</span><span style="color:#A6ACCD;"> myset</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">o</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="插入值" tabindex="-1">插入值 <a class="header-anchor" href="#插入值" aria-label="Permalink to &quot;插入值&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">setV</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">List</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">boys</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> boys </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> boysMapper</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">selectList</span><span style="color:#89DDFF;">(null);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//1、通过redisTemplate设置值</span></span>
<span class="line"><span style="color:#A6ACCD;">    boys</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">forEach</span><span style="color:#89DDFF;">((</span><span style="color:#A6ACCD;">boy</span><span style="color:#89DDFF;">)</span><span style="color:#C792EA;">-&gt;</span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForSet</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">add</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">boys</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">boy</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">});</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//设置过期时间</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">expire</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">setKey1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">200</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">SECONDS</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205080932368.png" alt="image-20220508093219291" style="zoom:80%;"><h3 id="获取值-1" tabindex="-1">获取值 <a class="header-anchor" href="#获取值-1" aria-label="Permalink to &quot;获取值&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">getV</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//1、通过redisTemplate获取值</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Set</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Object</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> boys </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForSet</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">members</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">boys</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">boys </span><span style="color:#89DDFF;">!=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">null)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        boys</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">forEach</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;font-style:italic;">::</span><span style="color:#A6ACCD;">println</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205080936757.png" alt="image-20220508093618705" style="zoom:80%;"><h3 id="其他方法" tabindex="-1">其他方法 <a class="header-anchor" href="#其他方法" aria-label="Permalink to &quot;其他方法&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testSetM</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//根据value从一个set中查询,是否存在</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Boolean</span><span style="color:#A6ACCD;"> isEmpty </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForSet</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">isMember</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">boys</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">setValue2</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//获取Set缓存的长度</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> size </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForSet</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">size</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">boys</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//移除指定的元素</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> result1 </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForSet</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">remove</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">boys</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">setValue1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//移除指定的key</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Boolean</span><span style="color:#A6ACCD;"> result2 </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">delete</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">boys</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//获取过期时间</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> time </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getExpire</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">boys</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">time</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">isEmpty</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">size</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">result1</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">result2</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205080938445.png" alt="image-20220508093833393" style="zoom:80%;"><h2 id="list类型" tabindex="-1">List类型 <a class="header-anchor" href="#list类型" aria-label="Permalink to &quot;List类型&quot;">​</a></h2><h3 id="存储值-2" tabindex="-1">存储值 <a class="header-anchor" href="#存储值-2" aria-label="Permalink to &quot;存储值&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">/**</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"> * 操作List类型的数据</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">*/</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testList</span><span style="color:#89DDFF;">(){</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">ListOperations</span><span style="color:#A6ACCD;"> listOperations </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForList</span><span style="color:#89DDFF;">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//存值</span></span>
<span class="line"><span style="color:#A6ACCD;">    listOperations</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">leftPush</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">mylist</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">a</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    listOperations</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">leftPushAll</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">mylist</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">b</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">c</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">d</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//取值</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">List</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> mylist </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> listOperations</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">range</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">mylist</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">-</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">for</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> value </span><span style="color:#89DDFF;font-style:italic;">:</span><span style="color:#A6ACCD;"> mylist</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">value</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//获得列表长度 llen</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> size </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> listOperations</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">size</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">mylist</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> lSize </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> size</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">intValue</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">for</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">&lt;</span><span style="color:#A6ACCD;"> lSize</span><span style="color:#89DDFF;">;</span><span style="color:#A6ACCD;"> i</span><span style="color:#89DDFF;">++)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">//出队列</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> element </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">String</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> listOperations</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">rightPop</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">mylist</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">element</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h4 id="分条存储" tabindex="-1">分条存储 <a class="header-anchor" href="#分条存储" aria-label="Permalink to &quot;分条存储&quot;">​</a></h4><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testList</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//1、通过redisTemplate设置值</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">List</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">boys</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> boys </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> boysMapper</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">selectList</span><span style="color:#89DDFF;">(null);</span></span>
<span class="line"><span style="color:#A6ACCD;">    boys</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">forEach</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">boy </span><span style="color:#C792EA;">-&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForList</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">leftPush</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">boys</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">boy</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">});</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//设置过期时间，填入集合名称</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">expire</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">boys</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">100</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">MINUTES</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205072248109.png" alt="image-20220507224805048" style="zoom:80%;"><h4 id="批量存储" tabindex="-1">批量存储 <a class="header-anchor" href="#批量存储" aria-label="Permalink to &quot;批量存储&quot;">​</a></h4><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testList</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//2、将list集合放入缓存</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">ArrayList</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Object</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> list1 </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">ArrayList</span><span style="color:#89DDFF;">&lt;&gt;();</span></span>
<span class="line"><span style="color:#A6ACCD;">    admin a </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">admin</span><span style="color:#89DDFF;">(</span><span style="color:#F78C6C;">22</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">sda</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">213</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    list1</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">add</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">a</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    list1</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">add</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">张三</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    list1</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">add</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">李四</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForList</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">leftPushAll</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">list1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">String</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">valueOf</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">list1</span><span style="color:#89DDFF;">));</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//设置过期时间，填入集合名称</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">expire</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">list1</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">100</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;">TimeUnit</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">MINUTES</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="获取值-2" tabindex="-1">获取值 <a class="header-anchor" href="#获取值-2" aria-label="Permalink to &quot;获取值&quot;">​</a></h3><h4 id="获取所有内容" tabindex="-1">获取所有内容 <a class="header-anchor" href="#获取所有内容" aria-label="Permalink to &quot;获取所有内容&quot;">​</a></h4><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testSearchList</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//获取所有内容</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">List</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Object</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> boys </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForList</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">range</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">boys</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">0</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">-</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">boys </span><span style="color:#89DDFF;">!=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">null)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        boys</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">forEach</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;font-style:italic;">::</span><span style="color:#A6ACCD;">println</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205072256550.png" alt="image-20220507225600494" style="zoom:80%;"><h4 id="左右弹出元素" tabindex="-1">左右弹出元素 <a class="header-anchor" href="#左右弹出元素" aria-label="Permalink to &quot;左右弹出元素&quot;">​</a></h4><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testSearchList</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//左右各弹出一个元素</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Object</span><span style="color:#A6ACCD;"> b1 </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForList</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">leftPop</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">boys</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span><span style="color:#A6ACCD;">  </span><span style="color:#676E95;font-style:italic;">//从左侧弹出一个元素</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Object</span><span style="color:#A6ACCD;"> b2 </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForList</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">rightPop</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">boys</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;">//从右侧弹出一个元素</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">b1</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">b2</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205072257384.png" alt="image-20220507225745328" style="zoom:80%;"><h4 id="根据索引查询元素" tabindex="-1">根据索引查询元素 <a class="header-anchor" href="#根据索引查询元素" aria-label="Permalink to &quot;根据索引查询元素&quot;">​</a></h4><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testSearchList</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//根据索引查询元素</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Object</span><span style="color:#A6ACCD;"> listKey4 </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForList</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">index</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">boys</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">listKey4</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205072258567.png" alt="image-20220507225837511" style="zoom:80%;"><h4 id="获取列表长度" tabindex="-1">获取列表长度 <a class="header-anchor" href="#获取列表长度" aria-label="Permalink to &quot;获取列表长度&quot;">​</a></h4><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testSearchList</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//获取List缓存的长度</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> size </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForList</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">size</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">boys</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">list的长度：</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;">size</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h4 id="根据索引修改元素值" tabindex="-1">根据索引修改元素值 <a class="header-anchor" href="#根据索引修改元素值" aria-label="Permalink to &quot;根据索引修改元素值&quot;">​</a></h4><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testSearchList</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//根据索引修改List中的某条数据(key，索引，值)</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForList</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">set</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">list</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">java</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="删除值" tabindex="-1">删除值 <a class="header-anchor" href="#删除值" aria-label="Permalink to &quot;删除值&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">//移除N个值为value(key,移除个数，值)</span></span>
<span class="line"><span style="color:#A6ACCD;">redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForList</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">remove</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">list</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">3L</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">value</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span></code></pre></div><h2 id="zset类型-排序" tabindex="-1">Zset类型(排序) <a class="header-anchor" href="#zset类型-排序" aria-label="Permalink to &quot;Zset类型(排序)&quot;">​</a></h2><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">/**</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"> * 操作ZSet类型的数据</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">*/</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testZset</span><span style="color:#89DDFF;">(){</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">ZSetOperations</span><span style="color:#A6ACCD;"> zSetOperations </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForZSet</span><span style="color:#89DDFF;">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//存值</span></span>
<span class="line"><span style="color:#A6ACCD;">    zSetOperations</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">add</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">myZset</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">a</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">10.0</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    zSetOperations</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">add</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">myZset</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">b</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">11.0</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    zSetOperations</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">add</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">myZset</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">c</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">12.0</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    zSetOperations</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">add</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">myZset</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">a</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">13.0</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//取值</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Set</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> myZset </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> zSetOperations</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">range</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">myZset</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">-</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">for</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> s </span><span style="color:#89DDFF;font-style:italic;">:</span><span style="color:#A6ACCD;"> myZset</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">s</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//修改分数</span></span>
<span class="line"><span style="color:#A6ACCD;">    zSetOperations</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">incrementScore</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">myZset</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">b</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">20.0</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//取值</span></span>
<span class="line"><span style="color:#A6ACCD;">    myZset </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> zSetOperations</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">range</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">myZset</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">-</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">for</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> s </span><span style="color:#89DDFF;font-style:italic;">:</span><span style="color:#A6ACCD;"> myZset</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">s</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//删除成员</span></span>
<span class="line"><span style="color:#A6ACCD;">    zSetOperations</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">remove</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">myZset</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">a</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">b</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//取值</span></span>
<span class="line"><span style="color:#A6ACCD;">    myZset </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> zSetOperations</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">range</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">myZset</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">-</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">for</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> s </span><span style="color:#89DDFF;font-style:italic;">:</span><span style="color:#A6ACCD;"> myZset</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">s</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="存储值-3" tabindex="-1">存储值 <a class="header-anchor" href="#存储值-3" aria-label="Permalink to &quot;存储值&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testZsetInsert</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//查询所有用户</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">List</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">boys</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> boys </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> boysMapper</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">selectList</span><span style="color:#89DDFF;">(null);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//使用lambda表达式的方式遍历</span></span>
<span class="line"><span style="color:#A6ACCD;">    boys</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">forEach</span><span style="color:#89DDFF;">((</span><span style="color:#A6ACCD;">boy</span><span style="color:#89DDFF;">)</span><span style="color:#C792EA;">-&gt;</span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">//第一个参数是集合名、第二个参数是每一条数据、第三条分数是分数</span></span>
<span class="line"><span style="color:#A6ACCD;">        redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForZSet</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">add</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">boy</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> boy</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> boy</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getUserCP</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">});</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205072201230.png" alt="image-20220507220143150" style="zoom:67%;"><h3 id="获取值-3" tabindex="-1">获取值 <a class="header-anchor" href="#获取值-3" aria-label="Permalink to &quot;获取值&quot;">​</a></h3><h4 id="获取值-不带分数" tabindex="-1">获取值(不带分数) <a class="header-anchor" href="#获取值-不带分数" aria-label="Permalink to &quot;获取值(不带分数)&quot;">​</a></h4><p>打印全部内容(不包含分数)</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testSearch</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//按照排名先后(从小到大)打印指定区间内的元素, -1为打印全部</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Set</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Object</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> set </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForZSet</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">range</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">boy</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">0</span><span style="color:#89DDFF;">,-</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//查询到不为空，才能进行遍历</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">set </span><span style="color:#89DDFF;">!=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">null</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">){</span></span>
<span class="line"><span style="color:#A6ACCD;">        set</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">forEach</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;font-style:italic;">::</span><span style="color:#A6ACCD;">println</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205072206576.png" alt="image-20220507220609511" style="zoom:80%;"><h4 id="获取值-带分数" tabindex="-1">获取值(带分数) <a class="header-anchor" href="#获取值-带分数" aria-label="Permalink to &quot;获取值(带分数)&quot;">​</a></h4><p>返回集合内元素的排名，以及分数（从小到大）</p><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testSearch</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Set</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">ZSetOperations</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">TypedTuple</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Object</span><span style="color:#89DDFF;">&gt;&gt;</span><span style="color:#A6ACCD;"> set </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForZSet</span><span style="color:#89DDFF;">()</span></span>
<span class="line"><span style="color:#A6ACCD;">                                     </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">rangeWithScores</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">boy</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">-</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">for</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">ZSetOperations</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">TypedTuple</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Object</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> set1 </span><span style="color:#89DDFF;font-style:italic;">:</span><span style="color:#A6ACCD;"> set</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">set1</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getValue</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;"> : </span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;"> set1</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getScore</span><span style="color:#89DDFF;">());</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205072216316.png" alt="image-20220507221619250" style="zoom:80%;"><h4 id="获取指定分数范围" tabindex="-1">获取指定分数范围 <a class="header-anchor" href="#获取指定分数范围" aria-label="Permalink to &quot;获取指定分数范围&quot;">​</a></h4><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testSearch1</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//返回集合内元素在指定分数范围内的排名（从小到大）</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Set</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Object</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> byScore </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForZSet</span><span style="color:#89DDFF;">()</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">rangeByScore</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">boy</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">0D</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">100D</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//带偏移量和个数，(key，起始分数，最大分数，偏移量，个数)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Set</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">Object</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> byScore1 </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForZSet</span><span style="color:#89DDFF;">()</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">rangeByScore</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">boy</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0D</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">100D</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">3</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">byScore</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">byScore1</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205072239804.png" alt="image-20220507223905745" style="zoom:80%;"><h3 id="相关个数、排名统计" tabindex="-1">相关个数、排名统计 <a class="header-anchor" href="#相关个数、排名统计" aria-label="Permalink to &quot;相关个数、排名统计&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testSearch</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//返回集合内的成员个数</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> size </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForZSet</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">size</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">zSetKey</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//获得指定元素的分数:1.0,double类型</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Double</span><span style="color:#A6ACCD;"> score </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForZSet</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">score</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">zSetKey</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">张三</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//返回集合内指定分数范围的成员个数（Double类型）</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> count1 </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForZSet</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">count</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">zSetKey</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0D</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">3D</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//返回指定成员的排名</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//从小到大</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> startRank </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForZSet</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">rank</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">zSetKey</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">李四</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//从大到小</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">Long</span><span style="color:#A6ACCD;"> endRank </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForZSet</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">reverseRank</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">zSetKey</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">张三</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">startRank</span><span style="color:#89DDFF;">+</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">---</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;">endRank</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    System</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">out</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">println</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">size</span><span style="color:#89DDFF;">+</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">--</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;">score</span><span style="color:#89DDFF;">+</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">--</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;">count1</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220304162259622.png" alt="image-20220304162259622" style="zoom:80%;"><h3 id="删除值-1" tabindex="-1">删除值 <a class="header-anchor" href="#删除值-1" aria-label="Permalink to &quot;删除值&quot;">​</a></h3><h4 id="删除全部" tabindex="-1">删除全部 <a class="header-anchor" href="#删除全部" aria-label="Permalink to &quot;删除全部&quot;">​</a></h4><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testDelete</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">delete</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">boy</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h4 id="删除指定分数" tabindex="-1">删除指定分数 <a class="header-anchor" href="#删除指定分数" aria-label="Permalink to &quot;删除指定分数&quot;">​</a></h4><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testDelete</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//删除指定分数范围的元素（double类型）</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForZSet</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">removeRangeByScore</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">boy</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">8</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">12</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h4 id="删除指定索引" tabindex="-1">删除指定索引 <a class="header-anchor" href="#删除指定索引" aria-label="Permalink to &quot;删除指定索引&quot;">​</a></h4><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testDelete</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">//删除指定索引范围的元素（Long类型）</span></span>
<span class="line"><span style="color:#A6ACCD;">    redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForZSet</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">removeRange</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">boy</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">0L</span><span style="color:#89DDFF;">,</span><span style="color:#F78C6C;">3L</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h2 id="springboot连接哨兵" tabindex="-1">SpringBoot连接哨兵 <a class="header-anchor" href="#springboot连接哨兵" aria-label="Permalink to &quot;SpringBoot连接哨兵&quot;">​</a></h2><blockquote><p>在Sentinel集群监管下的Redis主从集群，其节点会因为自动故障转移而发生变化，Redis的客户端必须感知这种变化，及时更新连接信息。<strong>Spring的RedisTemplate底层利用lettuce实现了节点的感知和自动切换</strong>。</p></blockquote><h3 id="_1-引入依赖" tabindex="-1">1 引入依赖 <a class="header-anchor" href="#_1-引入依赖" aria-label="Permalink to &quot;1 引入依赖&quot;">​</a></h3><p>在项目的pom文件中引入依赖：</p><div class="language-xml"><button title="Copy Code" class="copy"></button><span class="lang">xml</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">org.springframework.boot</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">spring-boot-starter-data-redis</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span></code></pre></div><h3 id="_2-配置redis地址" tabindex="-1">2 配置Redis地址 <a class="header-anchor" href="#_2-配置redis地址" aria-label="Permalink to &quot;2 配置Redis地址&quot;">​</a></h3><p>然后在配置文件application.yml中指定redis的sentinel相关信息：</p><blockquote><p>注意：这边配置的不是redis集群地址(7001、7002、7003)，而是sentinel地址(27001)</p></blockquote><div class="language-yml"><button title="Copy Code" class="copy"></button><span class="lang">yml</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F07178;">spring</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F07178;">redis</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F07178;">sentinel</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">      </span><span style="color:#F07178;">master</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">mymaster</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;"># 指定master名称</span></span>
<span class="line"><span style="color:#A6ACCD;">      </span><span style="color:#F07178;">nodes</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#676E95;font-style:italic;"># 指定redis-sentinel集群信息</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">192.168.22.130:27001</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">192.168.22.130:27002</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">192.168.22.130:27003</span></span></code></pre></div><h3 id="_3-配置读写分离-集群也要配置" tabindex="-1">3 配置读写分离(集群也要配置) <a class="header-anchor" href="#_3-配置读写分离-集群也要配置" aria-label="Permalink to &quot;3 配置读写分离(集群也要配置)&quot;">​</a></h3><p>在项目的启动类中，添加一个新的bean：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209171232762.png" alt="image-20220917123240643" style="zoom:80%;"><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Bean</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">LettuceClientConfigurationBuilderCustomizer</span><span style="color:#A6ACCD;"> </span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#82AAFF;">clientConfigurationBuilderCustomizer</span><span style="color:#89DDFF;">(){</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> clientConfigurationBuilder </span><span style="color:#C792EA;">-&gt;</span><span style="color:#A6ACCD;"> </span></span>
<span class="line"><span style="color:#A6ACCD;">          clientConfigurationBuilder</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">readFrom</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">ReadFrom</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">REPLICA_PREFERRED</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><p>这个bean中配置的就是读写策略，包括四种：</p><blockquote><ul><li>MASTER：从主节点读取</li><li>MASTER_PREFERRED：优先从master节点读取，master不可用才读取replica</li><li>REPLICA：从slave（replica）节点读取</li><li>REPLICA _PREFERRED：优先从slave（replica）节点读取，所有的slave都不可用才读取master</li></ul></blockquote><h3 id="_4-访问测试" tabindex="-1">4 访问测试 <a class="header-anchor" href="#_4-访问测试" aria-label="Permalink to &quot;4 访问测试&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">import</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">org</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">springframework</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">beans</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">factory</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">annotation</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">Autowired</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#F78C6C;">import</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">org</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">springframework</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">data</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">redis</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">core</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">StringRedisTemplate</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#F78C6C;">import</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">org</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">springframework</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">web</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">bind</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">annotation</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">GetMapping</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#F78C6C;">import</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">org</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">springframework</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">web</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">bind</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">annotation</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">PathVariable</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#F78C6C;">import</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">org</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">springframework</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">web</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">bind</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">annotation</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">RestController</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">RestController</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">HelloController</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Autowired</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">StringRedisTemplate</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">GetMapping</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">/get/{key}</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">hi</span><span style="color:#89DDFF;">(@</span><span style="color:#C792EA;">PathVariable</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">key</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForValue</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">get</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">key</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">GetMapping</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">/set/{key}/{value}</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">hi</span><span style="color:#89DDFF;">(@</span><span style="color:#C792EA;">PathVariable</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">key</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">PathVariable</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">value</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        redisTemplate</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">opsForValue</span><span style="color:#89DDFF;">().</span><span style="color:#82AAFF;">set</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">key</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> value</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">success</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><p>进行访问：</p><p>:8080/set/name/zhangsan</p><p>:8080/get/name</p><p>成功完成测试</p><h2 id="redission-实战" tabindex="-1">Redission 实战 <a class="header-anchor" href="#redission-实战" aria-label="Permalink to &quot;Redission 实战&quot;">​</a></h2><p>详细源码「码哥」上传到 GitHub 了：<a href="https://github.com/MageByte-Zero/springboot-parent-pom.git" target="_blank" rel="noreferrer">https://github.com/MageByte-Zero/springboot-parent-pom.git</a></p><h3 id="pom-依赖" tabindex="-1">pom 依赖 <a class="header-anchor" href="#pom-依赖" aria-label="Permalink to &quot;pom 依赖&quot;">​</a></h3><div class="language-xml"><button title="Copy Code" class="copy"></button><span class="lang">xml</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">org.redisson</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">redisson-spring-boot-starter</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">version</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">3.16.7</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">version</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">org.projectlombok</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">groupId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">&lt;</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;">lombok</span><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">artifactId</span><span style="color:#89DDFF;">&gt;</span></span>
<span class="line"><span style="color:#89DDFF;">&lt;/</span><span style="color:#F07178;">dependency</span><span style="color:#89DDFF;">&gt;</span></span></code></pre></div><div class="language-yml"><button title="Copy Code" class="copy"></button><span class="lang">yml</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F07178;">spring</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F07178;">application</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F07178;">name</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">redission</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F07178;">redis</span><span style="color:#89DDFF;">:</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F07178;">host</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">127.0.0.1</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F07178;">port</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">6379</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F07178;">ssl</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#FF9CAC;">false</span></span></code></pre></div><h3 id="定义service" tabindex="-1">定义Service <a class="header-anchor" href="#定义service" aria-label="Permalink to &quot;定义Service&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">import</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">org</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">redisson</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">api</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">RHyperLogLog</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#F78C6C;">import</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">org</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">redisson</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">api</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">RedissonClient</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#F78C6C;">import</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">org</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">springframework</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">beans</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">factory</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">annotation</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">Autowired</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#F78C6C;">import</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">org</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">springframework</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">stereotype</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">Service</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F78C6C;">import</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">java</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">util</span><span style="color:#89DDFF;">.</span><span style="color:#C792EA;">List</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Service</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">HyperLogLogService</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Autowired</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">RedissonClient</span><span style="color:#A6ACCD;"> redissonClient</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">    /**</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     * 将数据添加到 HyperLogLog</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     *</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     * </span><span style="color:#F78C6C;font-style:italic;">@param</span><span style="color:#676E95;font-style:italic;"> </span><span style="color:#A6ACCD;font-style:italic;">logName</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     * </span><span style="color:#F78C6C;font-style:italic;">@param</span><span style="color:#676E95;font-style:italic;"> </span><span style="color:#A6ACCD;font-style:italic;">item</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     * </span><span style="color:#F78C6C;font-style:italic;">@param</span><span style="color:#676E95;font-style:italic;"> </span><span style="color:#A6ACCD;font-style:italic;">&lt;T&gt;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     */</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">T</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">add</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">logName</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">T</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">item</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">RHyperLogLog</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">T</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> hyperLogLog </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redissonClient</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getHyperLogLog</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">logName</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        hyperLogLog</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">add</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">item</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">    /**</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     * 将集合数据添加到 HyperLogLog</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     * </span><span style="color:#F78C6C;font-style:italic;">@param</span><span style="color:#676E95;font-style:italic;"> </span><span style="color:#A6ACCD;font-style:italic;">logName</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     * </span><span style="color:#F78C6C;font-style:italic;">@param</span><span style="color:#676E95;font-style:italic;"> </span><span style="color:#A6ACCD;font-style:italic;">items</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     * </span><span style="color:#F78C6C;font-style:italic;">@param</span><span style="color:#676E95;font-style:italic;"> </span><span style="color:#A6ACCD;font-style:italic;">&lt;T&gt;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     */</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">T</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">addAll</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">logName</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">List</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">T</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">items</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">RHyperLogLog</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">T</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> hyperLogLog </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redissonClient</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getHyperLogLog</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">logName</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        hyperLogLog</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">addAll</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">items</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">    /**</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     * 将 otherLogNames 的 log 合并到 logName</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     *</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     * </span><span style="color:#F78C6C;font-style:italic;">@param</span><span style="color:#676E95;font-style:italic;"> </span><span style="color:#A6ACCD;font-style:italic;">logName</span><span style="color:#676E95;font-style:italic;">       当前 log</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     * </span><span style="color:#F78C6C;font-style:italic;">@param</span><span style="color:#676E95;font-style:italic;"> </span><span style="color:#A6ACCD;font-style:italic;">otherLogNames</span><span style="color:#676E95;font-style:italic;"> 需要合并到当前 log 的其他 logs</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     * </span><span style="color:#F78C6C;font-style:italic;">@param</span><span style="color:#676E95;font-style:italic;"> </span><span style="color:#A6ACCD;font-style:italic;">&lt;T&gt;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     */</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">T</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">merge</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">logName</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">...</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">otherLogNames</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">RHyperLogLog</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">T</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> hyperLogLog </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redissonClient</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getHyperLogLog</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">logName</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        hyperLogLog</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">mergeWith</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">otherLogNames</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">    /**</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     * 统计基数</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     *</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     * </span><span style="color:#F78C6C;font-style:italic;">@param</span><span style="color:#676E95;font-style:italic;"> </span><span style="color:#A6ACCD;font-style:italic;">logName</span><span style="color:#676E95;font-style:italic;"> 需要统计的 logName</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     * </span><span style="color:#F78C6C;font-style:italic;">@param</span><span style="color:#676E95;font-style:italic;"> </span><span style="color:#A6ACCD;font-style:italic;">&lt;T&gt;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     * </span><span style="color:#F78C6C;font-style:italic;">@return</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">     */</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">T</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">long</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">count</span><span style="color:#89DDFF;">(</span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> </span><span style="color:#A6ACCD;font-style:italic;">logName</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">RHyperLogLog</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">T</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> hyperLogLog </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> redissonClient</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">getHyperLogLog</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">logName</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#89DDFF;font-style:italic;">return</span><span style="color:#A6ACCD;"> hyperLogLog</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">count</span><span style="color:#89DDFF;">();</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div><h3 id="单元测试" tabindex="-1">单元测试 <a class="header-anchor" href="#单元测试" aria-label="Permalink to &quot;单元测试&quot;">​</a></h3><div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Slf4j</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">RunWith</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">SpringRunner</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">class</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">SpringBootTest</span><span style="color:#89DDFF;">(</span><span style="color:#FFCB6B;">classes</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> RedissionApplication</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">class</span><span style="color:#89DDFF;">)</span></span>
<span class="line"><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">class</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">HyperLogLogTest</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Autowired</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">private</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">HyperLogLogService</span><span style="color:#A6ACCD;"> hyperLogLogService</span><span style="color:#89DDFF;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testAdd</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> logName </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">码哥字节:Redis为什么这么快:uv</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> item </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">肖菜鸡</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">        hyperLogLogService</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">add</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">logName</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> item</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        log</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">info</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">添加元素[{}]到 log [{}] 中。</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> item</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> logName</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testCount</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> logName </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">码哥字节:Redis为什么这么快:uv</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">long</span><span style="color:#A6ACCD;"> count </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> hyperLogLogService</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">count</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">logName</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        log</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">info</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">logName = {} count = {}.</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> logName</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> count</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">@</span><span style="color:#C792EA;">Test</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#C792EA;">public</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">void</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">testMerge</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">ArrayList</span><span style="color:#89DDFF;">&lt;</span><span style="color:#C792EA;">String</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> items </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;font-style:italic;">new</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">ArrayList</span><span style="color:#89DDFF;">&lt;&gt;();</span></span>
<span class="line"><span style="color:#A6ACCD;">        items</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">add</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">肖菜鸡</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        items</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">add</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">谢霸哥</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        items</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">add</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">陈小白</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> otherLogName </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">码哥字节:Redis多线程模型原理与实战:uv</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">        hyperLogLogService</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">addAll</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">otherLogName</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> items</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        log</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">info</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">添加 {} 个元素到 log [{}] 中。</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> items</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">size</span><span style="color:#89DDFF;">(),</span><span style="color:#A6ACCD;"> otherLogName</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">String</span><span style="color:#A6ACCD;"> logName </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">码哥字节:Redis为什么这么快:uv</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">        hyperLogLogService</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">merge</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">logName</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> otherLogName</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        log</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">info</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">将 {} 合并到 {}.</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> otherLogName</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> logName</span><span style="color:#89DDFF;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#C792EA;">long</span><span style="color:#A6ACCD;"> count </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> hyperLogLogService</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">count</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">logName</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        log</span><span style="color:#89DDFF;">.</span><span style="color:#82AAFF;">info</span><span style="color:#89DDFF;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">合并后的 count = {}.</span><span style="color:#89DDFF;">&quot;</span><span style="color:#89DDFF;">,</span><span style="color:#A6ACCD;"> count</span><span style="color:#89DDFF;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">}</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span></code></pre></div></div></div></main><footer class="VPDocFooter" data-v-6b87e69f data-v-37656e44><!--[--><!--]--><!----><nav class="prev-next" data-v-37656e44><div class="pager" data-v-37656e44><a class="pager-link prev" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E5%8E%9F%E7%90%86.html" data-v-37656e44><span class="desc" data-v-37656e44>Previous page</span><span class="title" data-v-37656e44>Redis原理</span></a></div><div class="pager" data-v-37656e44><a class="pager-link next" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E5%AE%9E%E6%88%98.html" data-v-37656e44><span class="desc" data-v-37656e44>Next page</span><span class="title" data-v-37656e44>Redis实战</span></a></div></nav></footer><!--[--><!--]--></div></div></div><!--[--><!--]--></div></div><!----><!--[--><!--]--></div></div>
    <script>window.__VP_HASH_MAP__=JSON.parse("{\"2、数据库_mysql_mysql面试_基础.md\":\"40da680a\",\"1、学前端_5、小程序_小程序项目.md\":\"60a1629b\",\"1、学前端_4、node_知识篇.md\":\"a7fb500e\",\"1、学前端_2、js_ts_es6 进阶.md\":\"6d07ba10\",\"1、学前端_3、vue_vue3_vue3进阶.md\":\"7ac622b4\",\"5、运维_jenkins.md\":\"929081f8\",\"1、学前端_2、js_ts_typescript.md\":\"875a4aa4\",\"2、数据库_mysql_mysql核心_设计.md\":\"7faf46d1\",\"2、数据库_mysql_mysql核心_基础.md\":\"d8e97f3e\",\"1、学前端_1、html_css_html基础.md\":\"7584d076\",\"1、学前端_5、专题篇_问题篇.md\":\"e893aaa2\",\"2、数据库_mysql_mysql面试_进阶.md\":\"f934806d\",\"3、springboot_运维_原理.md\":\"f4a39db6\",\"2、数据库_influxdb.md\":\"6e1711e1\",\"3、springboot_新特性.md\":\"cdf3e307\",\"mybatis_mybatisplus_jpa.md\":\"8e41681b\",\"1、学前端_5、小程序_小程序优化.md\":\"a2185198\",\"2、数据库_redis_redis基础.md\":\"856df0e0\",\"linux_实用脚本.md\":\"f2299dd5\",\"4、微服务_必备_分布式基础.md\":\"d49863d5\",\"2、数据库_redis_redis优化.md\":\"e66ae32f\",\"4、微服务_springsecurity_进阶篇.md\":\"235a8e9e\",\"5、运维_chatgpt.md\":\"10db3823\",\"2、数据库_mysql_分库分表.md\":\"e1c8a095\",\"start.md\":\"9bc1ff8d\",\"5、运维_github.md\":\"2ec6c735\",\"java学前端_css.md\":\"f11b47f0\",\"1、学前端_5、专题篇_知识篇.md\":\"a463ed8d\",\"linux_软件部署.md\":\"d6722925\",\"2、数据库_neo4j.md\":\"97ad22ac\",\"team.md\":\"ce467a6a\",\"nginx_实战篇.md\":\"7785486e\",\"index.md\":\"8c3ec167\",\"计算机基础_计算机网络_网络基础.md\":\"7a54a85d\",\"1、学前端_4、node_进阶篇.md\":\"60f6db69\",\"java_java集合.md\":\"a049b313\",\"1、学前端_3、vue_vue3_vue3高级.md\":\"614d1516\",\"1、学前端_5、小程序_微信小程序.md\":\"9a4be771\",\"5、运维_netty.md\":\"12ca0278\",\"2、数据库_mysql_mysql核心_运维.md\":\"83f97c16\",\"idea_vs code.md\":\"afdcb593\",\"java学前端_vue3_组件.md\":\"1086884e\",\"idea_chrome.md\":\"4a32afbc\",\"云原生_k8s.md\":\"db58e65a\",\"2、数据库_mysql_mysql核心_进阶.md\":\"61d16dff\",\"ssm_springbatch.md\":\"f799ab4a\",\"三高_分布式.md\":\"db1b8a1b\",\"2、数据库_elasticsearch_1、es基础.md\":\"04d17448\",\"linux_linux基础.md\":\"4b0bf394\",\"idea_idea插件.md\":\"fa86e45a\",\"可视化 _ 监控_可视化大屏.md\":\"004553bd\",\"2、数据库_mongodb_整合.md\":\"3c47d7f4\",\"4、微服务_springsecurity_基础篇.md\":\"534a3401\",\"4、微服务_进阶.md\":\"69095c58\",\"计算机基础_计算机基础_操作系统.md\":\"0f75d113\",\"可视化 _ 监控_zabbix.md\":\"71f2270e\",\"nginx_基础篇.md\":\"c7d8bb50\",\"1、学前端_4、node_项目实战.md\":\"bc5065b8\",\"2、数据库_redis_redis原理.md\":\"5cedf685\",\"可视化 _ 监控_监控基础.md\":\"ac56ce4d\",\"三高_高并发.md\":\"ea9ffc99\",\"2、数据库_redis_redis高级.md\":\"1d5872f6\",\"1、学前端_4、node_基础篇.md\":\"581cc13a\",\"2、数据库_mongodb_基础.md\":\"fb7a0a29\",\"idea_idea基础.md\":\"6f2f9638\",\"4、微服务_必备_sentinel.md\":\"2edfbf6c\",\"2、数据库_elasticsearch_3、es高级.md\":\"ef146606\",\"1、学前端_3、vue_vue3_vue3新语法.md\":\"8afd5409\",\"消息中间件_canal.md\":\"3949163c\",\"ssm_maven.md\":\"2c5e12ed\",\"4、微服务_springsecurity_高级篇.md\":\"882d3ff3\",\"linux_linux进阶.md\":\"188ef7b4\",\"计算机基础_设计模式_uml.md\":\"634ba256\",\"计算机基础_算法_leetcode.md\":\"77162fb9\",\"项目实战_小兔鲜_进阶篇1.md\":\"17c52c81\",\"1、学前端_2、js_ts_es6 基础.md\":\"fda3f18b\",\"项目实战_小兔鲜_进阶篇2.md\":\"a0f23006\",\"软件测试_测试基础.md\":\"8c1060cd\",\"2、数据库_redis_本地缓存.md\":\"00617fe6\",\"nginx_面试篇.md\":\"e3fb373a\",\"mybatis_mybatisplus_mybatis.md\":\"9239e0ad\",\"linux_shell.md\":\"ae53d83b\",\"2、数据库_mysql_mysql核心_优化.md\":\"36230425\",\"项目实战_项目推荐.md\":\"f9d97630\",\"mybatis_mybatisplus_mybatisplus.md\":\"0030fd35\",\"项目实战_百度地图_进阶篇.md\":\"c8b93267\",\"三高_高可用.md\":\"323840c5\",\"java_java新特性.md\":\"22abf56d\",\"软件测试_压力测试.md\":\"9ab44440\",\"java学前端_html_js.md\":\"e0fcd240\",\"2、数据库_redis_redis实战.md\":\"d6daeeab\",\"nginx_进阶篇.md\":\"e6b63195\",\"三高_秒杀.md\":\"3878bb64\",\"5、运维_git.md\":\"0264925c\",\"java_java进阶.md\":\"e79cb5b4\",\"并发 _ 多线程_基础篇.md\":\"7adbfac5\",\"项目实战_百度地图_基础篇.md\":\"8afa5954\",\"java学前端_react.md\":\"3ec827dd\",\"1、学前端_1、html_css_css基础.md\":\"01b56712\",\"项目实战_小兔鲜_基础篇.md\":\"646f5df5\",\"1、学前端_2、js_ts_js 基础.md\":\"cb13e36f\",\"可视化 _ 监控_监控进阶.md\":\"0cdbc292\",\"计算机基础_设计模式_基础篇.md\":\"51617287\",\"计算机基础_数据结构_基础篇.md\":\"b2bfd8d4\",\"项目实战_苍穹外卖_进阶篇.md\":\"48415e41\",\"ssm_spring.md\":\"ab514659\",\"消息中间件_rabbitmq.md\":\"45b1eb28\",\"1、学前端_1、html_css_网页进阶.md\":\"db998248\",\"消息中间件_kafka.md\":\"b747dabf\",\"云原生_docker.md\":\"983c7ba7\",\"4、微服务_必备_分布式锁.md\":\"5af1cf8d\",\"消息中间件_rocketmq.md\":\"d441da85\",\"项目实战_黑马头条_基础篇.md\":\"b05af3a6\",\"ssm_springmvc.md\":\"81b9714f\",\"项目实战_支付.md\":\"1d7407dd\",\"项目实战_黑马头条_进阶篇2.md\":\"bff0015b\",\"项目实战_黑马头条_进阶篇.md\":\"19f18388\",\"java学前端_vue2_组件.md\":\"58c6b1df\",\"3、springboot_基础篇.md\":\"529c66f4\",\"3、springboot_应用篇.md\":\"8b92aa61\",\"项目实战_黑马头条_高级篇.md\":\"227c08c1\",\"1、学前端_5、小程序_uniapp.md\":\"71a282b4\",\"项目实战_云尚办公_基础篇.md\":\"1fe188ba\",\"并发 _ 多线程_并发完善.md\":\"26619c46\",\"1、学前端_2、js_ts_js 进阶.md\":\"657dfb8f\",\"java_java高级.md\":\"23782d1a\",\"java_java基础.md\":\"86d67c77\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"en-US\",\"dir\":\"ltr\",\"title\":\"VitePress\",\"description\":\"A VitePress site\",\"base\":\"/notebook/\",\"head\":[],\"appearance\":true,\"themeConfig\":{\"algolia\":{\"appId\":\"DW7O63I9IR\",\"apiKey\":\"f8ed758cdb288a8b06542bc35923c1a1\",\"indexName\":\"notebook\"},\"sidebar\":[{\"text\":\"Java\",\"collapsed\":true,\"items\":[{\"text\":\"Java基础\",\"link\":\"/Java/Java基础\"},{\"text\":\"Java新特性\",\"link\":\"/Java/Java新特性\"},{\"text\":\"Java进阶\",\"link\":\"/Java/Java进阶\"},{\"text\":\"Java集合\",\"link\":\"/Java/Java集合\"},{\"text\":\"Java高级\",\"link\":\"/Java/Java高级\"}]},{\"text\":\"Linux\",\"collapsed\":true,\"items\":[{\"text\":\"Linux基础\",\"link\":\"/Linux/Linux基础\"},{\"text\":\"Linux新特性\",\"link\":\"/Linux/Linux进阶\"},{\"text\":\"Shell脚本\",\"link\":\"/Linux/Shell\"},{\"text\":\"实用脚本\",\"link\":\"/Linux/实用脚本\"},{\"text\":\"软件部署\",\"link\":\"/Linux/软件部署\"}]},{\"text\":\"Nginx\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/Nginx/基础篇\"},{\"text\":\"进阶篇\",\"link\":\"/Nginx/进阶篇\"},{\"text\":\"实战篇\",\"link\":\"/Nginx/实战篇\"},{\"text\":\"面试篇\",\"link\":\"/Nginx/面试篇\"}]},{\"text\":\"SSM\",\"collapsed\":true,\"items\":[{\"text\":\"Maven\",\"link\":\"/SSM/Maven\"},{\"text\":\"Spring\",\"link\":\"/SSM/Spring\"},{\"text\":\"SpringMVC\",\"link\":\"/SSM/SpringMVC\"},{\"text\":\"SpringBatch\",\"link\":\"/SSM/SpringBatch\"}]},{\"text\":\"SpringBoot\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/3、SpringBoot/基础篇\"},{\"text\":\"应用篇\",\"link\":\"/3、SpringBoot/应用篇\"},{\"text\":\"新特性\",\"link\":\"/3、SpringBoot/新特性\"},{\"text\":\"运维&原理\",\"link\":\"/3、SpringBoot/运维&原理\"}]},{\"text\":\"SpringCloud\",\"collapsed\":true,\"items\":[{\"text\":\"SpringCloud\",\"link\":\"/4、微服务/进阶\"},{\"text\":\"Sentinel\",\"link\":\"/4、微服务/必备/Sentinel\"}]},{\"text\":\"SpringSecurity\",\"collapsed\":true,\"items\":[{\"text\":\"SpringSecurity基础篇\",\"link\":\"/4、微服务/SpringSecurity/基础篇\"},{\"text\":\"SpringSecurity进阶篇\",\"link\":\"/4、微服务/SpringSecurity/进阶篇\"},{\"text\":\"SpringSecurity高级篇\",\"link\":\"/4、微服务/SpringSecurity/高级篇\"}]},{\"text\":\"Mybatis & MybatisPlus\",\"collapsed\":true,\"items\":[{\"text\":\"Mybatis\",\"link\":\"/Mybatis&MybatisPlus/Mybatis\"},{\"text\":\"MybatisPlus\",\"link\":\"/Mybatis&MybatisPlus/MybatisPlus\"},{\"text\":\"JPA\",\"link\":\"/Mybatis&MybatisPlus/JPA\"}]},{\"text\":\"Git & ChatGPT\",\"collapsed\":true,\"items\":[{\"text\":\"Git\",\"link\":\"/5、运维/Git\"},{\"text\":\"Github\",\"link\":\"/5、运维/Github\"},{\"text\":\"ChatGPT\",\"link\":\"/5、运维/ChatGPT\"},{\"text\":\"Jenkins\",\"link\":\"/5、运维/Jenkins\"},{\"text\":\"Netty\",\"link\":\"/5、运维/Netty\"}]},{\"text\":\"数据库\",\"collapsed\":true,\"items\":[{\"text\":\"MySQL\",\"collapsed\":true,\"items\":[{\"text\":\"MySQL基础\",\"link\":\"/2、数据库/MySQL/MySQL核心/基础\"},{\"text\":\"MySQL进阶\",\"link\":\"/2、数据库/MySQL/MySQL核心/进阶\"},{\"text\":\"MySQL优化\",\"link\":\"/2、数据库/MySQL/MySQL核心/优化\"},{\"text\":\"MySQL设计\",\"link\":\"/2、数据库/MySQL/MySQL核心/设计\"},{\"text\":\"MySQL运维\",\"link\":\"/2、数据库/MySQL/MySQL核心/运维\"},{\"text\":\"分库分表\",\"link\":\"/2、数据库/MySQL/分库分表\"}]},{\"text\":\"Redis\",\"collapsed\":true,\"items\":[{\"text\":\"Redis基础\",\"link\":\"/2、数据库/Redis/Redis基础\"},{\"text\":\"Redis优化\",\"link\":\"/2、数据库/Redis/Redis优化\"},{\"text\":\"Redis原理\",\"link\":\"/2、数据库/Redis/Redis原理\"},{\"text\":\"Redis高级\",\"link\":\"/2、数据库/Redis/Redis高级\"},{\"text\":\"Redis实战\",\"link\":\"/2、数据库/Redis/Redis实战\"},{\"text\":\"本地缓存\",\"link\":\"/2、数据库/Redis/本地缓存\"}]},{\"text\":\"MongoDB\",\"collapsed\":true,\"items\":[{\"text\":\"MongoDB基础\",\"link\":\"/2、数据库/MongoDB/基础\"},{\"text\":\"MongoDB进阶\",\"link\":\"/2、数据库/MongoDB/整合\"}]},{\"text\":\"ElasticSearch\",\"collapsed\":true,\"items\":[{\"text\":\"ES基础\",\"link\":\"/2、数据库/ElasticSearch/1、ES基础\"},{\"text\":\"ES高级\",\"link\":\"/2、数据库/ElasticSearch/3、ES高级\"}]},{\"text\":\"InfluxDB\",\"link\":\"/2、数据库/influxdb\"},{\"text\":\"Neo4j\",\"link\":\"/2、数据库/Neo4j\"}]},{\"text\":\"高并发 & 秒杀 & 分布式\",\"collapsed\":true,\"items\":[{\"text\":\"分布式理论\",\"link\":\"/三高/分布式\"},{\"text\":\"分布式锁\",\"link\":\"/4、微服务/必备/分布式锁\"},{\"text\":\"秒杀\",\"link\":\"/三高/秒杀\"},{\"text\":\"高可用\",\"link\":\"/三高/高可用\"},{\"text\":\"高并发\",\"link\":\"/三高/高并发\"}]},{\"text\":\"云原生\",\"collapsed\":true,\"items\":[{\"text\":\"Docker\",\"link\":\"/云原生/Docker\"},{\"text\":\"K8S\",\"link\":\"/云原生/K8S\"}]},{\"text\":\"可视化 & 监控\",\"collapsed\":true,\"items\":[{\"text\":\"监控基础\",\"link\":\"/可视化 & 监控/监控基础\"},{\"text\":\"监控进阶\",\"link\":\"/可视化 & 监控/监控进阶\"},{\"text\":\"可视化大屏\",\"link\":\"/可视化 & 监控/可视化大屏\"},{\"text\":\"Zabbix\",\"link\":\"/可视化 & 监控/Zabbix\"}]},{\"text\":\"学前端\",\"collapsed\":true,\"items\":[{\"text\":\"HTML+CSS\",\"collapsed\":true,\"items\":[{\"text\":\"HTML基础\",\"link\":\"/1、学前端/1、HTML+CSS/HTML基础\"},{\"text\":\"CSS基础\",\"link\":\"/1、学前端/1、HTML+CSS/CSS基础\"},{\"text\":\"网页进阶\",\"link\":\"/1、学前端/1、HTML+CSS/网页进阶\"}]},{\"text\":\"JS+TS\",\"collapsed\":true,\"items\":[{\"text\":\"JS基础\",\"link\":\"/1、学前端/2、JS+TS/JS 基础\"},{\"text\":\"JS进阶\",\"link\":\"/1、学前端/2、JS+TS/JS 进阶\"},{\"text\":\"ES6基础\",\"link\":\"/1、学前端/2、JS+TS/ES6 基础\"},{\"text\":\"ES6进阶\",\"link\":\"/1、学前端/2、JS+TS/ES6 进阶\"},{\"text\":\"TS基础\",\"link\":\"/1、学前端/2、JS+TS/TypeScript\"}]},{\"text\":\"NodeJS\",\"collapsed\":true,\"items\":[{\"text\":\"Node基础\",\"link\":\"/1、学前端/4、Node/基础篇\"},{\"text\":\"Node进阶\",\"link\":\"/1、学前端/4、Node/进阶篇\"},{\"text\":\"项目实战\",\"link\":\"/1、学前端/4、Node/项目实战\"}]},{\"text\":\"Vue\",\"collapsed\":true,\"items\":[{\"text\":\"Vue3进阶\",\"link\":\"/1、学前端/3、Vue/Vue3/Vue3进阶\"},{\"text\":\"Vue3高级\",\"link\":\"/1、学前端/3、Vue/Vue3/Vue3高级\"},{\"text\":\"Vue3新语法\",\"link\":\"/1、学前端/3、Vue/Vue3/Vue3新语法\"},{\"text\":\"项目实战\",\"link\":\"/1、学前端/3、Vue/Vue2/Vue2项目\"}]},{\"text\":\"小程序\",\"collapsed\":true,\"items\":[{\"text\":\"小程序基础\",\"link\":\"/1、学前端/5、小程序/微信小程序\"},{\"text\":\"小程序优化\",\"link\":\"/1、学前端/5、小程序/小程序优化\"},{\"text\":\"uniapp\",\"link\":\"/1、学前端/5、小程序/uniapp\"},{\"text\":\"项目实战\",\"link\":\"/1、学前端/5、小程序/小程序项目\"}]}]},{\"text\":\"计算机基础\",\"collapsed\":true,\"items\":[{\"text\":\"数据结构\",\"link\":\"/计算机基础/数据结构/基础篇\"},{\"text\":\"操作系统\",\"link\":\"/计算机基础/计算机基础/操作系统\"},{\"text\":\"设计模式\",\"link\":\"/计算机基础/设计模式/基础篇\"},{\"text\":\"计算机网络\",\"link\":\"/计算机基础/计算机网络/网络基础\"},{\"text\":\"UML\",\"link\":\"/计算机基础/设计模式/UML\"},{\"text\":\"LeetCode\",\"link\":\"/计算机基础/算法/LeetCode\"}]},{\"text\":\"项目实战\",\"collapsed\":true,\"items\":[{\"text\":\"云尚办公\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/项目实战/云尚办公/基础篇\"}]},{\"text\":\"小兔鲜\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/项目实战/小兔鲜/基础篇\"},{\"text\":\"进阶篇1\",\"link\":\"/项目实战/小兔鲜/进阶篇1\"},{\"text\":\"进阶篇2\",\"link\":\"/项目实战/小兔鲜/进阶篇2\"}]},{\"text\":\"地图\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/项目实战/百度地图/基础篇\"},{\"text\":\"进阶篇\",\"link\":\"/项目实战/百度地图/进阶篇\"}]},{\"text\":\"苍穹外卖\",\"collapsed\":true,\"items\":[{\"text\":\"进阶篇\",\"link\":\"/项目实战/苍穹外卖/进阶篇\"}]},{\"text\":\"黑马头条\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/项目实战/黑马头条/基础篇\"},{\"text\":\"进阶篇\",\"link\":\"/项目实战/黑马头条/进阶篇\"},{\"text\":\"进阶篇2\",\"link\":\"/项目实战/黑马头条/进阶篇2\"},{\"text\":\"高级篇\",\"link\":\"/项目实战/黑马头条/高级篇\"}]},{\"text\":\"支付\",\"link\":\"/项目实战/支付\"},{\"text\":\"项目推荐\",\"link\":\"/项目实战/项目推荐\"}]},{\"text\":\"团队成员\",\"link\":\"/team\"}],\"siteTitle\":\"任硕的文档\",\"logo\":\"/Vue.png\",\"nav\":[{\"text\":\"Java学前端\",\"items\":[{\"items\":[{\"text\":\"HTML+JS\",\"link\":\"/Java学前端/HTML+JS\"},{\"text\":\"CSS\",\"link\":\"/Java学前端/CSS\"},{\"text\":\"Vue2+组件\",\"link\":\"/Java学前端/Vue2+组件\"},{\"text\":\"Vue3+组件\",\"link\":\"/Java学前端/Vue3+组件\"},{\"text\":\"React\",\"link\":\"/Java学前端/React\"}]}],\"activeMatch\":\"/Java/\"},{\"text\":\"软件测试\",\"items\":[{\"items\":[{\"text\":\"测试基础\",\"link\":\"/软件测试/测试基础\"},{\"text\":\"压力测试\",\"link\":\"/软件测试/压力测试\"}]}]},{\"text\":\"多线程\",\"items\":[{\"items\":[{\"text\":\"基础篇\",\"link\":\"/并发 & 多线程/基础篇\"},{\"text\":\"进阶篇\",\"link\":\"/并发 & 多线程/并发完善\"}]}]},{\"text\":\"开发工具\",\"items\":[{\"items\":[{\"text\":\"Chrome\",\"link\":\"/IDEA/Chrome\"},{\"text\":\"IDEA基础\",\"link\":\"/IDEA/IDEA基础\"},{\"text\":\"IDEA插件\",\"link\":\"/IDEA/IDEA插件\"},{\"text\":\"VS Code\",\"link\":\"/IDEA/VS Code\"}]}]},{\"text\":\"消息中间件\",\"items\":[{\"items\":[{\"text\":\"RabbitMQ\",\"link\":\"/消息中间件/RabbitMQ\"},{\"text\":\"RocketMQ\",\"link\":\"/消息中间件/RocketMQ\"},{\"text\":\"Kafka\",\"link\":\"/消息中间件/Kafka\"},{\"text\":\"Canal\",\"link\":\"/消息中间件/Canal\"}]}]}],\"socialLinks\":[{\"icon\":\"github\",\"link\":\"https://github.com/renshuo123/renshuo123.github.io\"},{\"icon\":\"twitter\",\"link\":\"#\"},{\"icon\":{\"svg\":\"<svg t=\\\"1676028692954\\\" class=\\\"icon\\\" ...</path></svg>\"},\"link\":\"https://github.com/\"}]},\"locales\":{},\"scrollOffset\":90,\"cleanUrls\":false}");</script>
    
  </body>
</html>